• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
4  *
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.
9  *
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.
14  *
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.
19  */
20 
21 /**
22  * SECTION:element-gleffects.
23  * @title: gleffects.
24  *
25  * GL Shading Language effects.
26  *
27  * ## Examples
28  * |[
29  * gst-launch-1.0 videotestsrc ! glupload ! gleffects effect=5 ! glimagesink
30  * ]|
31  * FBO (Frame Buffer Object) and GLSL (OpenGL Shading Language) are required.
32  *
33  */
34 
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38 
39 #include "gstglelements.h"
40 #include "gstgleffects.h"
41 
42 #define GST_CAT_DEFAULT gst_gl_effects_debug
43 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
44 
45 enum
46 {
47   PROP_0 = 0x0,
48   PROP_EFFECT = 0x1 << 1,
49   PROP_HSWAP = 0x1 << 2,
50   PROP_INVERT = 0x1 << 3
51 };
52 
53 #define DEBUG_INIT \
54   GST_DEBUG_CATEGORY_INIT (gst_gl_effects_debug, "gleffects", 0, "gleffects element");
55 
56 #define gst_gl_effects_parent_class parent_class
57 G_DEFINE_TYPE_WITH_CODE (GstGLEffects, gst_gl_effects, GST_TYPE_GL_FILTER,
58     DEBUG_INIT);
59 
60 static gboolean
gst_element_init_gleffects(GstPlugin * plugin)61 gst_element_init_gleffects (GstPlugin * plugin)
62 {
63   gl_element_init (plugin);
64   return gst_gl_effects_register_filters (plugin, GST_RANK_NONE);
65 }
66 
67 GST_ELEMENT_REGISTER_DEFINE_CUSTOM (gleffects, gst_element_init_gleffects);
68 
69 static void gst_gl_effects_set_property (GObject * object, guint prop_id,
70     const GValue * value, GParamSpec * pspec);
71 static void gst_gl_effects_get_property (GObject * object, guint prop_id,
72     GValue * value, GParamSpec * pspec);
73 
74 static gboolean gst_gl_effects_init_resources (GstBaseTransform * trans);
75 static gboolean gst_gl_effects_reset_resources (GstBaseTransform * trans);
76 
77 static gboolean gst_gl_effects_on_init_gl_context (GstGLFilter * filter);
78 
79 static void gst_gl_effects_ghash_func_clean (gpointer key, gpointer value,
80     gpointer data);
81 
82 static gboolean gst_gl_effects_filter_texture (GstGLFilter * filter,
83     GstGLMemory * in_tex, GstGLMemory * out_tex);
84 static gboolean gst_gl_effects_filters_is_property_supported (const
85     GstGLEffectsFilterDescriptor *, gint property);
86 
87 /* dont' forget to edit the following when a new effect is added */
88 typedef enum
89 {
90   GST_GL_EFFECT_IDENTITY,
91   GST_GL_EFFECT_MIRROR,
92   GST_GL_EFFECT_SQUEEZE,
93   GST_GL_EFFECT_STRETCH,
94   GST_GL_EFFECT_TUNNEL,
95   GST_GL_EFFECT_FISHEYE,
96   GST_GL_EFFECT_TWIRL,
97   GST_GL_EFFECT_BULGE,
98   GST_GL_EFFECT_SQUARE,
99   GST_GL_EFFECT_HEAT,
100   GST_GL_EFFECT_SEPIA,
101   GST_GL_EFFECT_XPRO,
102   GST_GL_EFFECT_LUMA_XPRO,
103   GST_GL_EFFECT_XRAY,
104   GST_GL_EFFECT_SIN,
105   GST_GL_EFFECT_GLOW,
106   GST_GL_EFFECT_SOBEL,
107   GST_GL_EFFECT_BLUR,
108   GST_GL_EFFECT_LAPLACIAN,
109   GST_GL_N_EFFECTS
110 } GstGLEffectsEffect;
111 
112 static const GEnumValue *
gst_gl_effects_get_effects(void)113 gst_gl_effects_get_effects (void)
114 {
115   static const GEnumValue effect_types[] = {
116     {GST_GL_EFFECT_IDENTITY, "Do nothing Effect", "identity"},
117     {GST_GL_EFFECT_MIRROR, "Mirror Effect", "mirror"},
118     {GST_GL_EFFECT_SQUEEZE, "Squeeze Effect", "squeeze"},
119     {GST_GL_EFFECT_STRETCH, "Stretch Effect", "stretch"},
120     {GST_GL_EFFECT_TUNNEL, "Light Tunnel Effect", "tunnel"},
121     {GST_GL_EFFECT_FISHEYE, "FishEye Effect", "fisheye"},
122     {GST_GL_EFFECT_TWIRL, "Twirl Effect", "twirl"},
123     {GST_GL_EFFECT_BULGE, "Bulge Effect", "bulge"},
124     {GST_GL_EFFECT_SQUARE, "Square Effect", "square"},
125     {GST_GL_EFFECT_HEAT, "Heat Signature Effect", "heat"},
126     {GST_GL_EFFECT_SEPIA, "Sepia Toning Effect", "sepia"},
127     {GST_GL_EFFECT_XPRO, "Cross Processing Effect", "xpro"},
128     {GST_GL_EFFECT_LUMA_XPRO, "Luma Cross Processing Effect", "lumaxpro"},
129     {GST_GL_EFFECT_XRAY, "Glowing negative effect", "xray"},
130     {GST_GL_EFFECT_SIN, "All Grey but Red Effect", "sin"},
131     {GST_GL_EFFECT_GLOW, "Glow Lighting Effect", "glow"},
132     {GST_GL_EFFECT_SOBEL, "Sobel edge detection Effect", "sobel"},
133     {GST_GL_EFFECT_BLUR, "Blur with 9x9 separable convolution Effect", "blur"},
134     {GST_GL_EFFECT_LAPLACIAN, "Laplacian Convolution Demo Effect", "laplacian"},
135     {0, NULL, NULL}
136   };
137   return effect_types;
138 }
139 
140 #define GST_TYPE_GL_EFFECTS_EFFECT (gst_gl_effects_effect_get_type ())
141 static GType
gst_gl_effects_effect_get_type(void)142 gst_gl_effects_effect_get_type (void)
143 {
144   static GType gl_effects_effect_type = 0;
145   if (!gl_effects_effect_type) {
146     gl_effects_effect_type =
147         g_enum_register_static ("GstGLEffectsEffect",
148         gst_gl_effects_get_effects ());
149   }
150   return gl_effects_effect_type;
151 }
152 
153 static void
gst_gl_effects_set_effect(GstGLEffects * effects,gint effect_type)154 gst_gl_effects_set_effect (GstGLEffects * effects, gint effect_type)
155 {
156   GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (effects);
157 
158   switch (effect_type) {
159     case GST_GL_EFFECT_IDENTITY:
160       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_identity;
161       filter_class->supported_gl_api =
162           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
163       effects->current_effect = effect_type;
164       break;
165     case GST_GL_EFFECT_MIRROR:
166       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_mirror;
167       filter_class->supported_gl_api =
168           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
169       effects->current_effect = effect_type;
170       break;
171     case GST_GL_EFFECT_SQUEEZE:
172       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_squeeze;
173       filter_class->supported_gl_api =
174           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
175       effects->current_effect = effect_type;
176       break;
177     case GST_GL_EFFECT_STRETCH:
178       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_stretch;
179       filter_class->supported_gl_api =
180           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
181       effects->current_effect = effect_type;
182       break;
183     case GST_GL_EFFECT_TUNNEL:
184       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_tunnel;
185       filter_class->supported_gl_api =
186           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
187       effects->current_effect = effect_type;
188       break;
189     case GST_GL_EFFECT_FISHEYE:
190       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_fisheye;
191       filter_class->supported_gl_api =
192           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
193       effects->current_effect = effect_type;
194       break;
195     case GST_GL_EFFECT_TWIRL:
196       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_twirl;
197       filter_class->supported_gl_api =
198           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
199       effects->current_effect = effect_type;
200       break;
201     case GST_GL_EFFECT_BULGE:
202       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_bulge;
203       filter_class->supported_gl_api =
204           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
205       effects->current_effect = effect_type;
206       break;
207     case GST_GL_EFFECT_SQUARE:
208       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_square;
209       filter_class->supported_gl_api =
210           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
211       effects->current_effect = effect_type;
212       break;
213     case GST_GL_EFFECT_HEAT:
214       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_heat;
215       filter_class->supported_gl_api =
216           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
217       effects->current_effect = effect_type;
218       break;
219     case GST_GL_EFFECT_SEPIA:
220       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sepia;
221       filter_class->supported_gl_api =
222           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
223       effects->current_effect = effect_type;
224       break;
225     case GST_GL_EFFECT_XPRO:
226       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_xpro;
227       filter_class->supported_gl_api =
228           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
229       effects->current_effect = effect_type;
230       break;
231     case GST_GL_EFFECT_LUMA_XPRO:
232       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_luma_xpro;
233       filter_class->supported_gl_api =
234           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
235       effects->current_effect = effect_type;
236       break;
237     case GST_GL_EFFECT_SIN:
238       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sin;
239       filter_class->supported_gl_api =
240           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
241       effects->current_effect = effect_type;
242       break;
243     case GST_GL_EFFECT_XRAY:
244       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_xray;
245       filter_class->supported_gl_api =
246           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
247       effects->current_effect = effect_type;
248       break;
249     case GST_GL_EFFECT_GLOW:
250       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_glow;
251       filter_class->supported_gl_api =
252           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
253       effects->current_effect = effect_type;
254       break;
255     case GST_GL_EFFECT_SOBEL:
256       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_sobel;
257       filter_class->supported_gl_api =
258           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
259       effects->current_effect = effect_type;
260       break;
261     case GST_GL_EFFECT_BLUR:
262       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_blur;
263       filter_class->supported_gl_api =
264           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
265       effects->current_effect = effect_type;
266       break;
267     case GST_GL_EFFECT_LAPLACIAN:
268       effects->effect = (GstGLEffectProcessFunc) gst_gl_effects_laplacian;
269       filter_class->supported_gl_api =
270           GST_GL_API_GLES2 | GST_GL_API_OPENGL | GST_GL_API_OPENGL3;
271       effects->current_effect = effect_type;
272       break;
273     default:
274       g_assert_not_reached ();
275   }
276 
277   effects->current_effect = effect_type;
278 }
279 
280 /* init resources that need a gl context */
281 static gboolean
gst_gl_effects_gl_start(GstGLBaseFilter * base_filter)282 gst_gl_effects_gl_start (GstGLBaseFilter * base_filter)
283 {
284   GstGLEffects *effects = GST_GL_EFFECTS (base_filter);
285   GstGLFilter *filter = GST_GL_FILTER (base_filter);
286   GstGLContext *context = base_filter->context;
287   GstGLBaseMemoryAllocator *base_alloc;
288   GstGLAllocationParams *params;
289   gint i;
290 
291   if (!GST_GL_BASE_FILTER_CLASS (parent_class)->gl_start (base_filter))
292     return FALSE;
293 
294   base_alloc = (GstGLBaseMemoryAllocator *)
295       gst_allocator_find (GST_GL_MEMORY_ALLOCATOR_NAME);
296   params =
297       (GstGLAllocationParams *) gst_gl_video_allocation_params_new (context,
298       NULL, &filter->out_info, 0, NULL, GST_GL_TEXTURE_TARGET_2D, GST_GL_RGBA);
299 
300   for (i = 0; i < NEEDED_TEXTURES; i++) {
301     if (effects->midtexture[i])
302       gst_memory_unref (GST_MEMORY_CAST (effects->midtexture[i]));
303 
304     effects->midtexture[i] =
305         (GstGLMemory *) gst_gl_base_memory_alloc (base_alloc, params);
306   }
307 
308   gst_object_unref (base_alloc);
309   gst_gl_allocation_params_free (params);
310 
311   return TRUE;
312 }
313 
314 /* free resources that need a gl context */
315 static void
gst_gl_effects_gl_stop(GstGLBaseFilter * base_filter)316 gst_gl_effects_gl_stop (GstGLBaseFilter * base_filter)
317 {
318   GstGLEffects *effects = GST_GL_EFFECTS (base_filter);
319   const GstGLFuncs *gl = base_filter->context->gl_vtable;
320   gint i = 0;
321 
322   for (i = 0; i < NEEDED_TEXTURES; i++) {
323     gst_memory_unref (GST_MEMORY_CAST (effects->midtexture[i]));
324   }
325 
326   for (i = 0; i < GST_GL_EFFECTS_N_CURVES; i++) {
327     gl->DeleteTextures (1, &effects->curve[i]);
328     effects->curve[i] = 0;
329   }
330 
331   GST_GL_BASE_FILTER_CLASS (parent_class)->gl_stop (base_filter);
332 }
333 
334 static void
gst_gl_effects_class_init(GstGLEffectsClass * klass)335 gst_gl_effects_class_init (GstGLEffectsClass * klass)
336 {
337   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
338 
339   gst_gl_filter_add_rgba_pad_templates (GST_GL_FILTER_CLASS (klass));
340 
341   GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_effects_init_resources;
342   GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_effects_reset_resources;
343 
344   GST_GL_BASE_FILTER_CLASS (klass)->gl_start = gst_gl_effects_gl_start;
345   GST_GL_BASE_FILTER_CLASS (klass)->gl_stop = gst_gl_effects_gl_stop;
346 
347   GST_GL_FILTER_CLASS (klass)->filter_texture = gst_gl_effects_filter_texture;
348   GST_GL_FILTER_CLASS (klass)->init_fbo = gst_gl_effects_on_init_gl_context;
349 
350   klass->filter_descriptor = NULL;
351 
352   gst_element_class_set_metadata (element_class,
353       "Gstreamer OpenGL Effects", "Filter/Effect/Video",
354       "GL Shading Language effects",
355       "Filippo Argiolas <filippo.argiolas@gmail.com>");
356 
357   GST_GL_BASE_FILTER_CLASS (klass)->supported_gl_api =
358       GST_GL_API_OPENGL | GST_GL_API_GLES2 | GST_GL_API_OPENGL3;
359 
360   gst_type_mark_as_plugin_api (GST_TYPE_GL_EFFECTS_EFFECT, 0);
361   gst_type_mark_as_plugin_api (GST_TYPE_GL_EFFECTS, 0);
362 }
363 
364 static void
gst_gl_effects_filter_class_init(GstGLEffectsClass * klass,const GstGLEffectsFilterDescriptor * filter_descriptor)365 gst_gl_effects_filter_class_init (GstGLEffectsClass * klass,
366     const GstGLEffectsFilterDescriptor * filter_descriptor)
367 {
368   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
369   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
370 
371   klass->filter_descriptor = filter_descriptor;
372 
373   gobject_class->set_property = gst_gl_effects_set_property;
374   gobject_class->get_property = gst_gl_effects_get_property;
375 
376   /* if filterDescriptor is null it's a generic gleffects */
377   if (!filter_descriptor) {
378     g_object_class_install_property (gobject_class,
379         PROP_EFFECT,
380         g_param_spec_enum ("effect",
381             "Effect",
382             "Select which effect apply to GL video texture",
383             GST_TYPE_GL_EFFECTS_EFFECT,
384             GST_GL_EFFECT_IDENTITY,
385             G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
386   } else {
387     gchar *description = g_strdup_printf ("GL Shading Language effects - %s",
388         filter_descriptor->filter_longname);
389 
390     gst_element_class_set_metadata (element_class,
391         filter_descriptor->filter_longname, "Filter/Effect/Video",
392         description, "Filippo Argiolas <filippo.argiolas@gmail.com>");
393 
394     g_free (description);
395   }
396 
397   g_object_class_install_property (gobject_class,
398       PROP_HSWAP,
399       g_param_spec_boolean ("hswap",
400           "Horizontal Swap",
401           "Switch video texture left to right, useful with webcams",
402           FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
403 
404   /* FIXME: make it work on every effect */
405   if (gst_gl_effects_filters_is_property_supported (filter_descriptor,
406           PROP_INVERT)) {
407     g_object_class_install_property (gobject_class, PROP_INVERT,
408         g_param_spec_boolean ("invert", "Invert the colors for sobel effect",
409             "Invert colors to get dark edges on bright background when using sobel effect",
410             FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
411   }
412 }
413 
414 static void
set_horizontal_swap(GstGLEffects * effects)415 set_horizontal_swap (GstGLEffects * effects)
416 {
417 #if GST_GL_HAVE_OPENGL
418   GstGLContext *context = GST_GL_BASE_FILTER (effects)->context;
419   const GstGLFuncs *gl = context->gl_vtable;
420 
421   if (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL) {
422     const gfloat mirrormatrix[16] = {
423       -1.0, 0.0, 0.0, 0.0,
424       0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0
425     };
426 
427     gl->MatrixMode (GL_MODELVIEW);
428     gl->LoadMatrixf (mirrormatrix);
429   }
430 #endif
431 }
432 
433 static void
gst_gl_effects_init(GstGLEffects * effects)434 gst_gl_effects_init (GstGLEffects * effects)
435 {
436   effects->horizontal_swap = FALSE;
437   effects->invert = FALSE;
438   effects->effect = gst_gl_effects_identity;
439 }
440 
441 static void
gst_gl_effects_filter_init(GstGLEffects * effects)442 gst_gl_effects_filter_init (GstGLEffects * effects)
443 {
444   gst_gl_effects_set_effect (effects,
445       GST_GL_EFFECTS_GET_CLASS (effects)->filter_descriptor->effect);
446 }
447 
448 static void
gst_gl_effects_ghash_func_clean(gpointer key,gpointer value,gpointer data)449 gst_gl_effects_ghash_func_clean (gpointer key, gpointer value, gpointer data)
450 {
451   GstGLShader *shader = (GstGLShader *) value;
452 
453   gst_object_unref (shader);
454 
455   value = NULL;
456 }
457 
458 static gboolean
gst_gl_effects_reset_resources(GstBaseTransform * trans)459 gst_gl_effects_reset_resources (GstBaseTransform * trans)
460 {
461   GstGLEffects *effects = GST_GL_EFFECTS (trans);
462 
463   /* release shaders in the gl thread */
464   g_hash_table_foreach (effects->shaderstable, gst_gl_effects_ghash_func_clean,
465       effects);
466 
467   /* clean the htable without calling values destructors
468    * because shaders have been released in the glthread
469    * through the foreach func */
470   g_hash_table_unref (effects->shaderstable);
471   effects->shaderstable = NULL;
472 
473   return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (trans);
474 }
475 
476 static void
gst_gl_effects_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)477 gst_gl_effects_set_property (GObject * object, guint prop_id,
478     const GValue * value, GParamSpec * pspec)
479 {
480   GstGLEffects *effects = GST_GL_EFFECTS (object);
481 
482   switch (prop_id) {
483     case PROP_EFFECT:
484       gst_gl_effects_set_effect (effects, g_value_get_enum (value));
485       break;
486     case PROP_HSWAP:
487       effects->horizontal_swap = g_value_get_boolean (value);
488       break;
489     case PROP_INVERT:
490       effects->invert = g_value_get_boolean (value);
491       break;
492     default:
493       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
494       break;
495   }
496 }
497 
498 static void
gst_gl_effects_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)499 gst_gl_effects_get_property (GObject * object, guint prop_id,
500     GValue * value, GParamSpec * pspec)
501 {
502   GstGLEffects *effects = GST_GL_EFFECTS (object);
503 
504   switch (prop_id) {
505     case PROP_EFFECT:
506       g_value_set_enum (value, effects->current_effect);
507       break;
508     case PROP_HSWAP:
509       g_value_set_boolean (value, effects->horizontal_swap);
510       break;
511     case PROP_INVERT:
512       g_value_set_boolean (value, effects->invert);
513       break;
514     default:
515       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
516       break;
517   }
518 }
519 
520 static gboolean
gst_gl_effects_init_resources(GstBaseTransform * trans)521 gst_gl_effects_init_resources (GstBaseTransform * trans)
522 {
523   GstGLEffects *effects = GST_GL_EFFECTS (trans);
524   gint i;
525 
526   effects->shaderstable = g_hash_table_new (g_str_hash, g_str_equal);
527 
528   for (i = 0; i < NEEDED_TEXTURES; i++) {
529     effects->midtexture[i] = 0;
530   }
531   for (i = 0; i < GST_GL_EFFECTS_N_CURVES; i++) {
532     effects->curve[i] = 0;
533   }
534 
535   return GST_BASE_TRANSFORM_CLASS (parent_class)->start (trans);
536 }
537 
538 static gboolean
gst_gl_effects_on_init_gl_context(GstGLFilter * filter)539 gst_gl_effects_on_init_gl_context (GstGLFilter * filter)
540 {
541   return TRUE;
542 }
543 
544 static gboolean
gst_gl_effects_filter_texture(GstGLFilter * filter,GstGLMemory * in_tex,GstGLMemory * out_tex)545 gst_gl_effects_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex,
546     GstGLMemory * out_tex)
547 {
548   GstGLEffects *effects = GST_GL_EFFECTS (filter);
549 
550   effects->intexture = in_tex;
551   effects->outtexture = out_tex;
552 
553   if (effects->horizontal_swap == TRUE)
554     set_horizontal_swap (effects);
555 
556   effects->effect (effects);
557 
558   return TRUE;
559 }
560 
561 GstGLShader *
gst_gl_effects_get_fragment_shader(GstGLEffects * effects,const gchar * shader_name,const gchar * shader_source_gles2)562 gst_gl_effects_get_fragment_shader (GstGLEffects * effects,
563     const gchar * shader_name, const gchar * shader_source_gles2)
564 {
565   GstGLShader *shader = NULL;
566   GstGLFilter *filter = GST_GL_FILTER (effects);
567   GstGLContext *context = GST_GL_BASE_FILTER (filter)->context;
568 
569   shader = g_hash_table_lookup (effects->shaderstable, shader_name);
570 
571   if (!shader) {
572     GError *error = NULL;
573     const gchar *frag_strs[2];
574 
575     frag_strs[0] =
576         gst_gl_shader_string_get_highest_precision (context,
577         GST_GLSL_VERSION_NONE,
578         GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY);
579     frag_strs[1] = shader_source_gles2;
580 
581     if (!(shader = gst_gl_shader_new_link_with_stages (context, &error,
582                 gst_glsl_stage_new_default_vertex (context),
583                 gst_glsl_stage_new_with_strings (context, GL_FRAGMENT_SHADER,
584                     GST_GLSL_VERSION_NONE,
585                     GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, 2,
586                     frag_strs), NULL))) {
587       GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND,
588           ("Failed to initialize %s shader", shader_name), (NULL));
589     }
590 
591     filter->draw_attr_position_loc =
592         gst_gl_shader_get_attribute_location (shader, "a_position");
593     filter->draw_attr_texture_loc =
594         gst_gl_shader_get_attribute_location (shader, "a_texcoord");
595   }
596 
597   g_hash_table_insert (effects->shaderstable, (gchar *) shader_name, shader);
598 
599   return shader;
600 }
601 
602 static const GstGLEffectsFilterDescriptor *
gst_gl_effects_filters_supported_properties(void)603 gst_gl_effects_filters_supported_properties (void)
604 {
605   /* Horizontal swap property is supported by all filters */
606   static const GstGLEffectsFilterDescriptor effects[] = {
607     {GST_GL_EFFECT_SOBEL, PROP_INVERT, NULL},
608     {GST_GL_EFFECT_LAPLACIAN, PROP_INVERT, NULL},
609     {0, 0, NULL}
610   };
611   return effects;
612 }
613 
614 static inline gboolean
gst_gl_effects_filters_is_property_supported(const GstGLEffectsFilterDescriptor * descriptor,gint property)615 gst_gl_effects_filters_is_property_supported (const GstGLEffectsFilterDescriptor
616     * descriptor, gint property)
617 {
618   /* generic filter (NULL descriptor) supports all properties */
619   return !descriptor || (descriptor->supported_properties & property);
620 }
621 
622 static const GstGLEffectsFilterDescriptor *
gst_gl_effects_filters_descriptors(void)623 gst_gl_effects_filters_descriptors (void)
624 {
625   static GstGLEffectsFilterDescriptor *descriptors = NULL;
626   if (!descriptors) {
627     const GEnumValue *e;
628     const GEnumValue *effect = gst_gl_effects_get_effects ();
629     const GstGLEffectsFilterDescriptor *defined;
630     guint n_filters = 0, i;
631 
632     for (e = effect; NULL != e->value_nick; ++e, ++n_filters) {
633     }
634 
635     descriptors = g_new0 (GstGLEffectsFilterDescriptor, n_filters + 1);
636     for (i = 0; i < n_filters; ++i, ++effect) {
637       descriptors[i].effect = effect->value;
638       descriptors[i].filter_name = effect->value_nick;
639       descriptors[i].filter_longname = effect->value_name;
640     }
641 
642     for (defined = gst_gl_effects_filters_supported_properties ();
643         0 != defined->supported_properties; ++defined) {
644 
645       for (i = 0; i < n_filters; ++i) {
646         if (descriptors[i].effect == defined->effect) {
647           descriptors[i].supported_properties = defined->supported_properties;
648           break;
649         }
650       }
651       if (i >= n_filters) {
652         GST_WARNING ("Could not match gstgleffects-%s descriptor",
653             defined->filter_name);
654       }
655     }
656   }
657   return descriptors;
658 }
659 
660 gboolean
gst_gl_effects_register_filters(GstPlugin * plugin,GstRank rank)661 gst_gl_effects_register_filters (GstPlugin * plugin, GstRank rank)
662 {
663   static gsize registered = 0;
664 
665   if (g_once_init_enter (&registered)) {
666     GTypeInfo info = {
667       sizeof (GstGLEffectsClass),
668       NULL,
669       NULL,
670       (GClassInitFunc) gst_gl_effects_filter_class_init,
671       NULL,
672       NULL,
673       sizeof (GstGLEffects),
674       0,
675       NULL
676     };
677     GType generic_type =
678         g_type_register_static (GST_TYPE_GL_EFFECTS, "GstGLEffectsGeneric",
679         &info, 0);
680 
681     if (gst_element_register (plugin, "gleffects", rank, generic_type)) {
682       const GstGLEffectsFilterDescriptor *filters;
683       for (filters = gst_gl_effects_filters_descriptors ();
684           NULL != filters->filter_name; ++filters) {
685         gchar *name = g_strdup_printf ("gleffects_%s", filters->filter_name);
686         GTypeInfo info = {
687           sizeof (GstGLEffectsClass),
688           NULL,
689           NULL,
690           (GClassInitFunc) gst_gl_effects_filter_class_init,
691           NULL,
692           filters,
693           sizeof (GstGLEffects),
694           0,
695           (GInstanceInitFunc) gst_gl_effects_filter_init
696         };
697         GType type =
698             g_type_register_static (GST_TYPE_GL_EFFECTS, name, &info, 0);
699         if (!gst_element_register (plugin, name, rank, type)) {
700           GST_WARNING ("Could not register %s", name);
701         }
702         g_free (name);
703       }
704     }
705     g_once_init_leave (&registered, generic_type);
706   }
707   return registered;
708 }
709