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 (®istered)) {
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 (®istered, generic_type);
706 }
707 return registered;
708 }
709