3 * Copyright (C) 2007 David Schleef <ds@schleef.org>
4 * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
5 * Copyright (C) 2008 Filippo Argiolas <filippo.argiolas@gmail.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
27 #include <gst/video/gstvideometa.h>
29 #include "gstglfilter.h"
31 #if GST_GL_HAVE_PLATFORM_EGL
32 #include "egl/gsteglimagememory.h"
35 #define GST_CAT_DEFAULT gst_gl_filter_debug
36 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
39 static GstStaticPadTemplate gst_gl_filter_src_pad_template =
40 GST_STATIC_PAD_TEMPLATE ("src",
43 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
44 (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
46 #if GST_GL_HAVE_PLATFORM_EGL
47 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
50 GST_VIDEO_CAPS_MAKE_WITH_FEATURES
51 (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
52 "RGBA") "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
55 static GstStaticPadTemplate gst_gl_filter_sink_pad_template =
56 GST_STATIC_PAD_TEMPLATE ("sink",
59 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
60 (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
62 #if GST_GL_HAVE_PLATFORM_EGL
63 GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_EGL_IMAGE,
66 GST_VIDEO_CAPS_MAKE_WITH_FEATURES
67 (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "RGBA") "; "
68 GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
79 GST_DEBUG_CATEGORY_INIT (gst_gl_filter_debug, "glfilter", 0, "glfilter element");
80 #define gst_gl_filter_parent_class parent_class
81 G_DEFINE_TYPE_WITH_CODE (GstGLFilter, gst_gl_filter, GST_TYPE_BASE_TRANSFORM,
84 static void gst_gl_filter_set_property (GObject * object, guint prop_id,
85 const GValue * value, GParamSpec * pspec);
86 static void gst_gl_filter_get_property (GObject * object, guint prop_id,
87 GValue * value, GParamSpec * pspec);
89 static void gst_gl_filter_set_context (GstElement * element,
90 GstContext * context);
91 static gboolean gst_gl_filter_query (GstBaseTransform * trans,
92 GstPadDirection direction, GstQuery * query);
93 static GstCaps *gst_gl_filter_transform_caps (GstBaseTransform * bt,
94 GstPadDirection direction, GstCaps * caps, GstCaps * filter);
95 static GstCaps *gst_gl_filter_fixate_caps (GstBaseTransform * bt,
96 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps);
97 static void gst_gl_filter_reset (GstGLFilter * filter);
98 static gboolean gst_gl_filter_start (GstBaseTransform * bt);
99 static gboolean gst_gl_filter_stop (GstBaseTransform * bt);
100 static gboolean gst_gl_filter_get_unit_size (GstBaseTransform * trans,
101 GstCaps * caps, gsize * size);
102 static GstFlowReturn gst_gl_filter_transform (GstBaseTransform * bt,
103 GstBuffer * inbuf, GstBuffer * outbuf);
104 static gboolean gst_gl_filter_propose_allocation (GstBaseTransform * trans,
105 GstQuery * decide_query, GstQuery * query);
106 static gboolean gst_gl_filter_decide_allocation (GstBaseTransform * trans,
108 static gboolean gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps,
111 /* GstGLContextThreadFunc */
112 static void gst_gl_filter_start_gl (GstGLContext * context, gpointer data);
113 static void gst_gl_filter_stop_gl (GstGLContext * context, gpointer data);
116 gst_gl_filter_class_init (GstGLFilterClass * klass)
118 GObjectClass *gobject_class;
119 GstElementClass *element_class;
121 gobject_class = (GObjectClass *) klass;
122 element_class = GST_ELEMENT_CLASS (klass);
124 gobject_class->set_property = gst_gl_filter_set_property;
125 gobject_class->get_property = gst_gl_filter_get_property;
127 GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
128 gst_gl_filter_transform_caps;
129 GST_BASE_TRANSFORM_CLASS (klass)->fixate_caps = gst_gl_filter_fixate_caps;
130 GST_BASE_TRANSFORM_CLASS (klass)->transform = gst_gl_filter_transform;
131 GST_BASE_TRANSFORM_CLASS (klass)->query = gst_gl_filter_query;
132 GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_filter_start;
133 GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_filter_stop;
134 GST_BASE_TRANSFORM_CLASS (klass)->set_caps = gst_gl_filter_set_caps;
135 GST_BASE_TRANSFORM_CLASS (klass)->propose_allocation =
136 gst_gl_filter_propose_allocation;
137 GST_BASE_TRANSFORM_CLASS (klass)->decide_allocation =
138 gst_gl_filter_decide_allocation;
139 GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = gst_gl_filter_get_unit_size;
141 element_class->set_context = gst_gl_filter_set_context;
143 gst_element_class_add_pad_template (element_class,
144 gst_static_pad_template_get (&gst_gl_filter_src_pad_template));
145 gst_element_class_add_pad_template (element_class,
146 gst_static_pad_template_get (&gst_gl_filter_sink_pad_template));
148 g_object_class_install_property (gobject_class, PROP_CONTEXT,
149 g_param_spec_object ("context",
151 "Get OpenGL context",
152 GST_GL_TYPE_CONTEXT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
154 klass->supported_gl_api = GST_GL_API_ANY;
155 klass->set_caps = NULL;
156 klass->filter = NULL;
157 klass->display_init_cb = NULL;
158 klass->display_reset_cb = NULL;
159 klass->onInitFBO = NULL;
160 klass->onStart = NULL;
161 klass->onStop = NULL;
162 klass->onReset = NULL;
163 klass->filter_texture = NULL;
167 gst_gl_filter_init (GstGLFilter * filter)
169 gst_gl_filter_reset (filter);
173 gst_gl_filter_set_property (GObject * object, guint prop_id,
174 const GValue * value, GParamSpec * pspec)
178 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
184 gst_gl_filter_get_property (GObject * object, guint prop_id,
185 GValue * value, GParamSpec * pspec)
187 GstGLFilter *filter = GST_GL_FILTER (object);
191 g_value_set_object (value, filter->context);
194 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
200 gst_gl_filter_set_context (GstElement * element, GstContext * context)
202 GstGLFilter *filter = GST_GL_FILTER (element);
203 GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter);
205 gst_gl_handle_set_context (element, context, &filter->display,
206 &filter->other_context);
208 gst_gl_display_filter_gl_api (filter->display,
209 filter_class->supported_gl_api);
213 gst_gl_filter_query (GstBaseTransform * trans, GstPadDirection direction,
216 GstGLFilter *filter = GST_GL_FILTER (trans);
217 GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter);
219 switch (GST_QUERY_TYPE (query)) {
220 case GST_QUERY_ALLOCATION:
222 if (direction == GST_PAD_SINK
223 && gst_base_transform_is_passthrough (trans))
224 return gst_pad_peer_query (GST_BASE_TRANSFORM_SRC_PAD (trans), query);
227 case GST_QUERY_CONTEXT:
229 gboolean ret = gst_gl_handle_context_query ((GstElement *) filter, query,
230 &filter->display, &filter->other_context);
232 gst_gl_display_filter_gl_api (filter->display,
233 filter_class->supported_gl_api);
240 return GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
245 gst_gl_filter_reset (GstGLFilter * filter)
247 GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter);
249 gst_caps_replace (&filter->out_caps, NULL);
251 if (filter->upload) {
252 gst_object_unref (filter->upload);
253 filter->upload = NULL;
256 if (filter->in_convert) {
257 gst_object_unref (filter->in_convert);
258 filter->in_convert = NULL;
261 if (filter->download) {
262 gst_object_unref (filter->download);
263 filter->download = NULL;
266 if (filter->uploaded_buffer) {
267 gst_buffer_unref (filter->uploaded_buffer);
268 filter->uploaded_buffer = NULL;
272 gst_object_unref (filter->pool);
276 if (filter->context) {
277 if (filter_class->onReset)
278 filter_class->onReset (filter);
280 if (filter_class->display_reset_cb != NULL) {
281 gst_gl_context_thread_add (filter->context, gst_gl_filter_stop_gl,
284 /* blocking call, delete the FBO */
285 if (filter->fbo != 0) {
286 gst_gl_context_del_fbo (filter->context, filter->fbo,
287 filter->depthbuffer);
290 if (filter->in_tex_id) {
291 gst_gl_context_del_texture (filter->context, &filter->in_tex_id);
292 filter->in_tex_id = 0;
295 if (filter->out_tex_id) {
296 gst_gl_context_del_texture (filter->context, &filter->out_tex_id);
297 filter->out_tex_id = 0;
300 gst_object_unref (filter->context);
301 filter->context = NULL;
304 if (filter->display) {
305 gst_object_unref (filter->display);
306 filter->display = NULL;
310 filter->depthbuffer = 0;
311 filter->default_shader = NULL;
312 filter->draw_attr_position_loc = -1;
313 filter->draw_attr_texture_loc = -1;
314 if (filter->other_context)
315 gst_object_unref (filter->other_context);
316 filter->other_context = NULL;
319 gst_object_unref (filter->context);
320 filter->context = NULL;
322 if (filter->in_converted_caps) {
323 gst_caps_unref (filter->in_converted_caps);
324 filter->in_converted_caps = NULL;
329 gst_gl_filter_start (GstBaseTransform * bt)
331 GstGLFilter *filter = GST_GL_FILTER (bt);
332 GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter);
334 if (!gst_gl_ensure_element_data (filter, &filter->display,
335 &filter->other_context))
338 gst_gl_display_filter_gl_api (filter->display,
339 filter_class->supported_gl_api);
341 if (filter_class->onStart)
342 filter_class->onStart (filter);
348 gst_gl_filter_stop (GstBaseTransform * bt)
350 GstGLFilter *filter = GST_GL_FILTER (bt);
351 GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter);
353 if (filter_class->onStop)
354 filter_class->onStop (filter);
356 gst_gl_filter_reset (filter);
362 gst_gl_filter_start_gl (GstGLContext * context, gpointer data)
364 GstGLFilter *filter = GST_GL_FILTER (data);
365 GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter);
367 filter_class->display_init_cb (filter);
371 gst_gl_filter_stop_gl (GstGLContext * context, gpointer data)
373 const GstGLFuncs *gl = context->gl_vtable;
374 GstGLFilter *filter = GST_GL_FILTER (data);
375 GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter);
377 filter_class->display_reset_cb (filter);
380 gl->DeleteVertexArrays (1, &filter->vao);
384 if (filter->vertex_buffer) {
385 gl->DeleteBuffers (1, &filter->vertex_buffer);
386 filter->vertex_buffer = 0;
391 gst_gl_filter_fixate_caps (GstBaseTransform * bt,
392 GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
394 GstStructure *ins, *outs;
395 const GValue *from_par, *to_par;
396 GValue fpar = { 0, }, tpar = {
399 othercaps = gst_caps_truncate (othercaps);
400 othercaps = gst_caps_make_writable (othercaps);
402 GST_DEBUG_OBJECT (bt, "trying to fixate othercaps %" GST_PTR_FORMAT
403 " based on caps %" GST_PTR_FORMAT, othercaps, caps);
405 ins = gst_caps_get_structure (caps, 0);
406 outs = gst_caps_get_structure (othercaps, 0);
408 from_par = gst_structure_get_value (ins, "pixel-aspect-ratio");
409 to_par = gst_structure_get_value (outs, "pixel-aspect-ratio");
411 /* If we're fixating from the sinkpad we always set the PAR and
412 * assume that missing PAR on the sinkpad means 1/1 and
413 * missing PAR on the srcpad means undefined
415 if (direction == GST_PAD_SINK) {
417 g_value_init (&fpar, GST_TYPE_FRACTION);
418 gst_value_set_fraction (&fpar, 1, 1);
422 g_value_init (&tpar, GST_TYPE_FRACTION);
423 gst_value_set_fraction (&tpar, 1, 1);
428 g_value_init (&tpar, GST_TYPE_FRACTION);
429 gst_value_set_fraction (&tpar, 1, 1);
432 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
436 g_value_init (&fpar, GST_TYPE_FRACTION);
437 gst_value_set_fraction (&fpar, 1, 1);
442 /* we have both PAR but they might not be fixated */
444 gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d;
446 gint from_dar_n, from_dar_d;
449 /* from_par should be fixed */
450 g_return_val_if_fail (gst_value_is_fixed (from_par), othercaps);
452 from_par_n = gst_value_get_fraction_numerator (from_par);
453 from_par_d = gst_value_get_fraction_denominator (from_par);
455 gst_structure_get_int (ins, "width", &from_w);
456 gst_structure_get_int (ins, "height", &from_h);
458 gst_structure_get_int (outs, "width", &w);
459 gst_structure_get_int (outs, "height", &h);
461 /* if both width and height are already fixed, we can't do anything
462 * about it anymore */
464 GST_DEBUG_OBJECT (bt, "dimensions already set to %dx%d, not fixating",
466 if (!gst_value_is_fixed (to_par)) {
467 GST_DEBUG_OBJECT (bt, "fixating to_par to %dx%d", 1, 1);
468 if (gst_structure_has_field (outs, "pixel-aspect-ratio"))
469 gst_structure_fixate_field_nearest_fraction (outs,
470 "pixel-aspect-ratio", 1, 1);
475 /* Calculate input DAR */
476 if (!gst_util_fraction_multiply (from_w, from_h, from_par_n, from_par_d,
477 &from_dar_n, &from_dar_d)) {
478 GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL),
479 ("Error calculating the output scaled size - integer overflow"));
483 GST_DEBUG_OBJECT (bt, "Input DAR is %d/%d", from_dar_n, from_dar_d);
485 /* If either width or height are fixed there's not much we
486 * can do either except choosing a height or width and PAR
487 * that matches the DAR as good as possible
492 GST_DEBUG_OBJECT (bt, "height is fixed (%d)", h);
494 if (!gst_value_is_fixed (to_par)) {
495 gst_value_set_fraction (&tpar, 1, 1);
498 /* PAR is fixed, choose the height that is nearest to the
499 * height with the same DAR */
500 to_par_n = gst_value_get_fraction_numerator (to_par);
501 to_par_d = gst_value_get_fraction_denominator (to_par);
503 GST_DEBUG_OBJECT (bt, "PAR is fixed %d/%d", to_par_n, to_par_d);
505 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
506 to_par_n, &num, &den)) {
507 GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL),
508 ("Error calculating the output scaled size - integer overflow"));
512 w = (guint) gst_util_uint64_scale_int (h, num, den);
513 gst_structure_fixate_field_nearest_int (outs, "width", w);
519 GST_DEBUG_OBJECT (bt, "width is fixed (%d)", w);
521 if (!gst_value_is_fixed (to_par)) {
522 gst_value_set_fraction (&tpar, 1, 1);
525 /* PAR is fixed, choose the height that is nearest to the
526 * height with the same DAR */
527 to_par_n = gst_value_get_fraction_numerator (to_par);
528 to_par_d = gst_value_get_fraction_denominator (to_par);
530 GST_DEBUG_OBJECT (bt, "PAR is fixed %d/%d", to_par_n, to_par_d);
532 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
533 to_par_n, &num, &den)) {
534 GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL),
535 ("Error calculating the output scaled size - integer overflow"));
539 h = (guint) gst_util_uint64_scale_int (w, den, num);
540 gst_structure_fixate_field_nearest_int (outs, "height", h);
543 } else if (gst_value_is_fixed (to_par)) {
545 gint set_h, set_w, f_h, f_w;
547 to_par_n = gst_value_get_fraction_numerator (to_par);
548 to_par_d = gst_value_get_fraction_denominator (to_par);
550 /* Calculate scale factor for the PAR change */
551 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_n,
552 to_par_d, &num, &den)) {
553 GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL),
554 ("Error calculating the output scaled size - integer overflow"));
558 /* Try to keep the input height */
559 tmp = gst_structure_copy (outs);
560 gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
561 gst_structure_get_int (tmp, "height", &set_h);
563 /* This might have failed but try to scale the width
564 * to keep the DAR nonetheless */
565 w = (guint) gst_util_uint64_scale_int (set_h, num, den);
566 gst_structure_fixate_field_nearest_int (tmp, "width", w);
567 gst_structure_get_int (tmp, "width", &set_w);
568 gst_structure_free (tmp);
570 /* We kept the DAR and the height is nearest to the original height */
572 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
573 G_TYPE_INT, set_h, NULL);
580 /* If the former failed, try to keep the input width at least */
581 tmp = gst_structure_copy (outs);
582 gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
583 gst_structure_get_int (tmp, "width", &set_w);
585 /* This might have failed but try to scale the width
586 * to keep the DAR nonetheless */
587 h = (guint) gst_util_uint64_scale_int (set_w, den, num);
588 gst_structure_fixate_field_nearest_int (tmp, "height", h);
589 gst_structure_get_int (tmp, "height", &set_h);
590 gst_structure_free (tmp);
592 /* We kept the DAR and the width is nearest to the original width */
594 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
595 G_TYPE_INT, set_h, NULL);
599 /* If all this failed, keep the height that was nearest to the orignal
600 * height and the nearest possible width. This changes the DAR but
601 * there's not much else to do here.
603 gst_structure_set (outs, "width", G_TYPE_INT, f_w, "height", G_TYPE_INT,
608 gint set_h, set_w, set_par_n, set_par_d, tmp2;
610 /* width, height and PAR are not fixed */
612 /* First try to keep the height and width as good as possible
614 tmp = gst_structure_copy (outs);
615 gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
616 gst_structure_get_int (tmp, "height", &set_h);
617 gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
618 gst_structure_get_int (tmp, "width", &set_w);
620 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, set_w,
621 &to_par_n, &to_par_d)) {
622 GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL),
623 ("Error calculating the output scaled size - integer overflow"));
624 gst_structure_free (tmp);
628 if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
629 gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
630 gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
632 gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
634 gst_structure_free (tmp);
636 if (set_par_n == to_par_n && set_par_d == to_par_d) {
637 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
638 G_TYPE_INT, set_h, NULL);
640 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
641 set_par_n != set_par_d)
642 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
643 set_par_n, set_par_d, NULL);
647 /* Otherwise try to scale width to keep the DAR with the set
649 if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
650 set_par_n, &num, &den)) {
651 GST_ELEMENT_ERROR (bt, CORE, NEGOTIATION, (NULL),
652 ("Error calculating the output scaled size - integer overflow"));
656 w = (guint) gst_util_uint64_scale_int (set_h, num, den);
657 tmp = gst_structure_copy (outs);
658 gst_structure_fixate_field_nearest_int (tmp, "width", w);
659 gst_structure_get_int (tmp, "width", &tmp2);
660 gst_structure_free (tmp);
663 gst_structure_set (outs, "width", G_TYPE_INT, tmp2, "height",
664 G_TYPE_INT, set_h, NULL);
665 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
666 set_par_n != set_par_d)
667 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
668 set_par_n, set_par_d, NULL);
672 /* ... or try the same with the height */
673 h = (guint) gst_util_uint64_scale_int (set_w, den, num);
674 tmp = gst_structure_copy (outs);
675 gst_structure_fixate_field_nearest_int (tmp, "height", h);
676 gst_structure_get_int (tmp, "height", &tmp2);
677 gst_structure_free (tmp);
680 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
681 G_TYPE_INT, tmp2, NULL);
682 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
683 set_par_n != set_par_d)
684 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
685 set_par_n, set_par_d, NULL);
689 /* If all fails we can't keep the DAR and take the nearest values
690 * for everything from the first try */
691 gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
692 G_TYPE_INT, set_h, NULL);
693 if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
694 set_par_n != set_par_d)
695 gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
696 set_par_n, set_par_d, NULL);
702 othercaps = gst_caps_fixate (othercaps);
704 GST_DEBUG_OBJECT (bt, "fixated othercaps to %" GST_PTR_FORMAT, othercaps);
706 if (from_par == &fpar)
707 g_value_unset (&fpar);
709 g_value_unset (&tpar);
715 gst_gl_filter_set_caps_features (const GstCaps * caps,
716 const gchar * feature_name)
718 GstCaps *ret = gst_gl_caps_replace_all_caps_features (caps, feature_name);
719 gst_caps_set_simple (ret, "format", G_TYPE_STRING, "RGBA", NULL);
724 gst_gl_filter_transform_caps (GstBaseTransform * bt,
725 GstPadDirection direction, GstCaps * caps, GstCaps * filter_caps)
727 GstGLFilter *filter = GST_GL_FILTER (bt);
729 GstCaps *result = NULL;
731 /* The following is the list of caps transformations performed. When
732 * direction == GST_PAD_SINK we start at the sinkpad and work toward the src
733 * pad and vice versa for direction == GST_PAD_SRC.
735 * sinkpad <-> (upload <-> convert) <-> filter (possible resize) <->
736 * (convert <-> download/output) <-> srcpad
738 if (direction == GST_PAD_SINK) {
740 gst_gl_upload_transform_caps (filter->context, direction, caps, NULL);
744 gst_gl_color_convert_transform_caps (filter->context, direction, tmp,
746 gst_caps_unref (tmp);
748 GstCaps *gl_caps = gst_caps_merge (gst_gl_filter_set_caps_features (caps,
749 GST_CAPS_FEATURE_MEMORY_GL_MEMORY),
750 gst_gl_filter_set_caps_features (caps,
751 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META));
754 gst_gl_download_transform_caps (filter->context, direction, caps, NULL);
756 result = gst_caps_merge (gl_caps, result);
759 GST_DEBUG_OBJECT (bt, "transfer returned caps %" GST_PTR_FORMAT, tmp);
761 if (direction == GST_PAD_SRC) {
763 gst_gl_color_convert_transform_caps (filter->context, direction, tmp,
765 gst_caps_unref (tmp);
768 gst_gl_upload_transform_caps (filter->context, direction, tmp, NULL);
770 GstCaps *gl_caps = gst_caps_merge (gst_gl_filter_set_caps_features (tmp,
771 GST_CAPS_FEATURE_MEMORY_GL_MEMORY),
772 gst_gl_filter_set_caps_features (tmp,
773 GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META));
776 gst_gl_download_transform_caps (filter->context, direction, tmp, NULL);
778 result = gst_caps_merge (gl_caps, result);
780 gst_caps_unref (tmp);
782 GST_DEBUG_OBJECT (bt, "transfer returned caps %" GST_PTR_FORMAT, tmp);
786 gst_caps_intersect_full (filter_caps, tmp, GST_CAPS_INTERSECT_FIRST);
787 gst_caps_unref (tmp);
792 GST_DEBUG_OBJECT (bt, "returning caps: %" GST_PTR_FORMAT, result);
799 gst_gl_filter_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
802 gboolean ret = FALSE;
805 ret = gst_video_info_from_caps (&info, caps);
807 *size = GST_VIDEO_INFO_SIZE (&info);
813 gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps,
817 GstGLFilterClass *filter_class;
819 filter = GST_GL_FILTER (bt);
820 filter_class = GST_GL_FILTER_GET_CLASS (filter);
822 if (!gst_video_info_from_caps (&filter->in_info, incaps))
824 if (!gst_video_info_from_caps (&filter->out_info, outcaps))
827 if (filter_class->set_caps) {
828 if (!filter_class->set_caps (filter, incaps, outcaps))
832 if (filter->out_caps && !gst_caps_is_equal (filter->out_caps, outcaps)) {
833 if (filter->upload) {
834 gst_object_unref (filter->upload);
835 filter->upload = NULL;
839 gst_caps_replace (&filter->out_caps, outcaps);
841 GST_DEBUG ("set_caps %dx%d", GST_VIDEO_INFO_WIDTH (&filter->out_info),
842 GST_VIDEO_INFO_HEIGHT (&filter->out_info));
849 GST_WARNING ("Wrong caps");
859 _ensure_input_chain (GstGLFilter * filter)
861 GstBaseTransform *bt = GST_BASE_TRANSFORM (filter);
863 if (!filter->upload) {
864 GstCapsFeatures *uploaded_features;
865 GstCaps *uploaded_caps;
866 GstCapsFeatures *converted_features;
867 GstVideoInfo converted_info;
868 GstCaps *in_caps = gst_pad_get_current_caps (bt->sinkpad);
870 filter->upload = gst_gl_upload_new (filter->context);
872 uploaded_caps = gst_caps_copy (in_caps);
874 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
875 gst_caps_set_features (uploaded_caps, 0, uploaded_features);
877 if (!gst_gl_upload_set_caps (filter->upload, in_caps, uploaded_caps)) {
878 gst_caps_unref (uploaded_caps);
879 gst_caps_unref (in_caps);
882 gst_caps_unref (in_caps);
884 if (!filter->in_convert) {
885 filter->in_convert = gst_gl_color_convert_new (filter->context);
888 gst_video_info_set_format (&converted_info, GST_VIDEO_FORMAT_RGBA,
889 GST_VIDEO_INFO_WIDTH (&filter->in_info),
890 GST_VIDEO_INFO_HEIGHT (&filter->in_info));
892 gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
894 if (filter->in_converted_caps)
895 gst_caps_unref (filter->in_converted_caps);
896 filter->in_converted_caps = gst_video_info_to_caps (&converted_info);
897 gst_caps_set_features (filter->in_converted_caps, 0, converted_features);
899 if (!gst_gl_color_convert_set_caps (filter->in_convert, uploaded_caps,
900 filter->in_converted_caps)) {
901 gst_caps_unref (uploaded_caps);
904 gst_caps_unref (uploaded_caps);
911 gst_gl_filter_propose_allocation (GstBaseTransform * trans,
912 GstQuery * decide_query, GstQuery * query)
914 GstGLFilter *filter = GST_GL_FILTER (trans);
915 GstStructure *config;
920 gst_query_parse_allocation (query, &caps, &need_pool);
929 /* we had a pool, check caps */
930 GST_DEBUG_OBJECT (filter, "check existing pool caps");
931 config = gst_buffer_pool_get_config (filter->pool);
932 gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
934 if (!gst_caps_is_equal (caps, pcaps)) {
935 GST_DEBUG_OBJECT (filter, "pool has different caps");
936 /* different caps, we can't use this pool */
937 gst_object_unref (filter->pool);
940 gst_structure_free (config);
943 if (filter->pool == NULL) {
946 if (!gst_video_info_from_caps (&info, caps))
949 /* the normal size of a frame */
952 GST_DEBUG_OBJECT (filter, "create new pool");
953 filter->pool = gst_gl_buffer_pool_new (filter->context);
955 config = gst_buffer_pool_get_config (filter->pool);
956 gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
958 if (!gst_buffer_pool_set_config (filter->pool, config))
962 gst_query_add_allocation_pool (query, filter->pool, size, 1, 0);
965 if (!_ensure_input_chain (filter))
968 gst_gl_upload_propose_allocation (filter->upload, decide_query, query);
970 if (filter->context->gl_vtable->FenceSync)
971 gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
978 GST_DEBUG_OBJECT (trans, "no caps specified");
983 GST_DEBUG_OBJECT (trans, "invalid caps specified");
988 GST_DEBUG_OBJECT (trans, "failed setting config");
994 gst_gl_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query)
996 GstGLFilter *filter = GST_GL_FILTER (trans);
997 GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter);
998 GstBufferPool *pool = NULL;
999 GstStructure *config;
1001 guint min, max, size;
1002 gboolean update_pool;
1004 GError *error = NULL;
1005 guint in_width, in_height, out_width, out_height;
1006 GstGLContext *other_context = NULL;
1007 gboolean same_downstream_gl_context = FALSE;
1009 gst_query_parse_allocation (query, &caps, NULL);
1013 if (!gst_gl_ensure_element_data (filter, &filter->display,
1014 &filter->other_context)) {
1018 gst_gl_display_filter_gl_api (filter->display,
1019 filter_class->supported_gl_api);
1021 if (gst_query_find_allocation_meta (query,
1022 GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) {
1023 GstGLContext *context;
1024 const GstStructure *upload_meta_params;
1029 gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params);
1030 if (upload_meta_params) {
1031 if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext",
1032 GST_GL_TYPE_CONTEXT, &context, NULL) && context) {
1033 GstGLContext *old = filter->context;
1035 filter->context = context;
1037 gst_object_unref (old);
1038 same_downstream_gl_context = TRUE;
1039 } else if (gst_structure_get (upload_meta_params, "gst.gl.context.handle",
1040 G_TYPE_POINTER, &handle, "gst.gl.context.type", G_TYPE_STRING,
1041 &type, "gst.gl.context.apis", G_TYPE_STRING, &apis, NULL)
1043 GstGLPlatform platform = GST_GL_PLATFORM_NONE;
1046 GST_DEBUG ("got GL context handle 0x%p with type %s and apis %s",
1047 handle, type, apis);
1049 platform = gst_gl_platform_from_string (type);
1050 gl_apis = gst_gl_api_from_string (apis);
1052 if (gl_apis && platform)
1054 gst_gl_context_new_wrapped (filter->display, (guintptr) handle,
1060 if (filter->other_context) {
1061 if (!other_context) {
1062 other_context = filter->other_context;
1064 GST_ELEMENT_WARNING (filter, LIBRARY, SETTINGS,
1065 ("%s", "Cannot share with more than one GL context"),
1066 ("%s", "Cannot share with more than one GL context"));
1070 if (!filter->context) {
1071 filter->context = gst_gl_context_new (filter->display);
1072 if (!gst_gl_context_create (filter->context, other_context, &error))
1076 in_width = GST_VIDEO_INFO_WIDTH (&filter->in_info);
1077 in_height = GST_VIDEO_INFO_HEIGHT (&filter->in_info);
1078 out_width = GST_VIDEO_INFO_WIDTH (&filter->out_info);
1079 out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info);
1082 gst_gl_context_del_fbo (filter->context, filter->fbo, filter->depthbuffer);
1084 filter->depthbuffer = 0;
1087 if (filter->in_tex_id) {
1088 gst_gl_context_del_texture (filter->context, &filter->in_tex_id);
1089 filter->in_tex_id = 0;
1092 if (filter->out_tex_id) {
1093 gst_gl_context_del_texture (filter->context, &filter->out_tex_id);
1094 filter->out_tex_id = 0;
1096 //blocking call, generate a FBO
1097 if (!gst_gl_context_gen_fbo (filter->context, out_width, out_height,
1098 &filter->fbo, &filter->depthbuffer))
1101 gst_gl_context_gen_texture (filter->context, &filter->in_tex_id,
1102 GST_VIDEO_FORMAT_RGBA, in_width, in_height);
1104 gst_gl_context_gen_texture (filter->context, &filter->out_tex_id,
1105 GST_VIDEO_FORMAT_RGBA, out_width, out_height);
1107 if (filter_class->display_init_cb != NULL) {
1108 gst_gl_context_thread_add (filter->context, gst_gl_filter_start_gl, filter);
1111 if (filter_class->onInitFBO) {
1112 if (!filter_class->onInitFBO (filter))
1116 if (gst_query_get_n_allocation_pools (query) > 0) {
1117 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
1123 gst_video_info_init (&vinfo);
1124 gst_video_info_from_caps (&vinfo, caps);
1127 update_pool = FALSE;
1130 if (!pool || (!same_downstream_gl_context
1131 && gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE,
1133 && !gst_buffer_pool_has_option (pool,
1134 GST_BUFFER_POOL_OPTION_GL_SYNC_META))) {
1135 /* can't use this pool */
1137 gst_object_unref (pool);
1138 pool = gst_gl_buffer_pool_new (filter->context);
1140 config = gst_buffer_pool_get_config (pool);
1142 gst_buffer_pool_config_set_params (config, caps, size, min, max);
1143 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
1144 if (gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL))
1145 gst_buffer_pool_config_add_option (config,
1146 GST_BUFFER_POOL_OPTION_GL_SYNC_META);
1147 gst_buffer_pool_config_add_option (config,
1148 GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
1150 gst_buffer_pool_set_config (pool, config);
1153 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
1155 gst_query_add_allocation_pool (query, pool, size, min, max);
1157 gst_object_unref (pool);
1163 GST_ELEMENT_ERROR (trans, RESOURCE, NOT_FOUND, ("%s", error->message),
1169 GST_ELEMENT_ERROR (trans, LIBRARY, INIT,
1170 ("Subclass failed to initialize."), (NULL));
1176 * gst_gl_filter_filter_texture:
1177 * @filter: a #GstGLFilter
1178 * @inbuf: an input buffer
1179 * @outbuf: an output buffer
1181 * Perform automatic upload if needed, call filter_texture vfunc and then an
1182 * automatic download if needed.
1184 * Returns: whether the transformation succeeded
1187 gst_gl_filter_filter_texture (GstGLFilter * filter, GstBuffer * inbuf,
1190 GstGLFilterClass *filter_class;
1191 guint in_tex, out_tex, out_tex_target;
1192 GstVideoFrame gl_frame, out_frame;
1193 GstVideoInfo gl_info;
1195 gboolean to_download =
1196 gst_caps_features_is_equal (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY,
1197 gst_caps_get_features (filter->out_caps, 0));
1198 GstMapFlags out_map_flags = GST_MAP_WRITE;
1199 GstBuffer *upload_buffer;
1201 filter_class = GST_GL_FILTER_GET_CLASS (filter);
1203 if (gst_gl_upload_perform_with_buffer (filter->upload, inbuf,
1204 &upload_buffer) != GST_GL_UPLOAD_DONE) {
1208 if (filter->uploaded_buffer) {
1209 gst_buffer_unref (filter->uploaded_buffer);
1210 filter->uploaded_buffer = NULL;
1213 filter->uploaded_buffer =
1214 gst_gl_color_convert_perform (filter->in_convert, upload_buffer);
1216 if (!filter->uploaded_buffer) {
1221 gst_video_info_from_caps (&gl_info, filter->in_converted_caps);
1223 if (!gst_video_frame_map (&gl_frame, &gl_info, filter->uploaded_buffer,
1224 GST_MAP_READ | GST_MAP_GL)) {
1229 in_tex = *(guint *) gl_frame.data[0];
1230 to_download |= !gst_is_gl_memory (gst_buffer_peek_memory (outbuf, 0));
1233 out_map_flags |= GST_MAP_GL;
1235 if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf,
1238 goto unmap_out_error;
1242 out_tex = *(guint *) out_frame.data[0];
1244 ((GstGLMemory *) gst_buffer_peek_memory (outbuf, 0))->tex_target;
1246 GST_LOG ("Output Buffer does not contain correct memory, "
1247 "attempting to wrap for download");
1249 if (!filter->download)
1250 filter->download = gst_gl_download_new (filter->context);
1252 gst_gl_download_set_format (filter->download, &out_frame.info);
1254 out_tex = filter->out_tex_id;
1255 out_tex_target = GL_TEXTURE_2D;
1258 GST_DEBUG ("calling filter_texture with textures in:%i out:%i", in_tex,
1261 g_assert (filter_class->filter_texture);
1262 ret = filter_class->filter_texture (filter, in_tex, out_tex);
1265 if (!gst_gl_download_perform_with_data (filter->download,
1266 out_tex, out_tex_target, out_frame.data)) {
1267 GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND,
1268 ("%s", "Failed to download video frame"), (NULL));
1273 gst_video_frame_unmap (&gl_frame);
1275 gst_video_frame_unmap (&out_frame);
1277 gst_gl_upload_release_buffer (filter->upload);
1278 gst_buffer_unref (upload_buffer);
1283 static GstFlowReturn
1284 gst_gl_filter_transform (GstBaseTransform * bt, GstBuffer * inbuf,
1287 GstGLFilter *filter;
1288 GstGLFilterClass *filter_class;
1289 GstGLSyncMeta *out_sync_meta, *in_sync_meta;
1291 filter = GST_GL_FILTER (bt);
1292 filter_class = GST_GL_FILTER_GET_CLASS (bt);
1294 if (!filter->display)
1295 return GST_FLOW_NOT_NEGOTIATED;
1297 g_assert (filter_class->filter || filter_class->filter_texture);
1299 in_sync_meta = gst_buffer_get_gl_sync_meta (inbuf);
1301 gst_gl_sync_meta_wait (in_sync_meta);
1303 if (!_ensure_input_chain (filter))
1304 return GST_FLOW_ERROR;
1306 if (filter_class->filter)
1307 filter_class->filter (filter, inbuf, outbuf);
1308 else if (filter_class->filter_texture)
1309 gst_gl_filter_filter_texture (filter, inbuf, outbuf);
1311 out_sync_meta = gst_buffer_get_gl_sync_meta (outbuf);
1313 gst_gl_sync_meta_set_sync_point (out_sync_meta, filter->context);
1327 /* convenience functions to simplify filter development */
1329 _glcb2 (gpointer data)
1331 struct glcb2 *cb = data;
1333 cb->func (cb->width, cb->height, cb->texture, cb->data);
1337 * gst_gl_filter_render_to_target:
1338 * @filter: a #GstGLFilter
1339 * @resize: whether to automatically resize the texture between the input size
1340 * and the output size
1341 * @input: the input texture
1342 * @target: the output texture
1343 * @func: the function to transform @input into @output. called with @data
1344 * @data: the data associated with @func
1346 * Transforms @input into @output using @func on through FBO. @resize should
1347 * only ever be %TRUE whenever @input is the input texture of @filter.
1350 gst_gl_filter_render_to_target (GstGLFilter * filter, gboolean resize,
1351 GLuint input, GLuint target, GLCB func, gpointer data)
1353 guint in_width, in_height, out_width, out_height;
1356 out_width = GST_VIDEO_INFO_WIDTH (&filter->out_info);
1357 out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info);
1359 in_width = GST_VIDEO_INFO_WIDTH (&filter->in_info);
1360 in_height = GST_VIDEO_INFO_HEIGHT (&filter->in_info);
1362 in_width = out_width;
1363 in_height = out_height;
1366 GST_LOG ("rendering to target. in %u, %ux%u out %u, %ux%u", input, in_width,
1367 in_height, target, out_width, out_height);
1372 cb.width = in_width;
1373 cb.height = in_height;
1375 gst_gl_context_use_fbo_v2 (filter->context, out_width, out_height,
1376 filter->fbo, filter->depthbuffer, target, _glcb2, &cb);
1380 _draw_with_shader_cb (gint width, gint height, guint texture, gpointer stuff)
1382 GstGLFilter *filter = GST_GL_FILTER (stuff);
1383 GstGLFuncs *gl = filter->context->gl_vtable;
1385 #if GST_GL_HAVE_OPENGL
1386 if (gst_gl_context_get_gl_api (filter->context) & GST_GL_API_OPENGL) {
1387 gl->MatrixMode (GL_PROJECTION);
1388 gl->LoadIdentity ();
1392 gst_gl_shader_use (filter->default_shader);
1394 gl->ActiveTexture (GL_TEXTURE1);
1395 gl->BindTexture (GL_TEXTURE_2D, texture);
1397 gst_gl_shader_set_uniform_1i (filter->default_shader, "tex", 1);
1398 gst_gl_shader_set_uniform_1f (filter->default_shader, "width", width);
1399 gst_gl_shader_set_uniform_1f (filter->default_shader, "height", height);
1401 gst_gl_filter_draw_texture (filter, texture, width, height);
1405 _get_attributes (GstGLFilter * filter)
1407 if (!filter->default_shader)
1410 if (filter->draw_attr_position_loc == -1)
1411 filter->draw_attr_position_loc =
1412 gst_gl_shader_get_attribute_location (filter->default_shader,
1415 if (filter->draw_attr_texture_loc == -1)
1416 filter->draw_attr_texture_loc =
1417 gst_gl_shader_get_attribute_location (filter->default_shader,
1422 * gst_gl_filter_render_to_target_with_shader:
1423 * @filter: a #GstGLFilter
1424 * @resize: whether to automatically resize the texture between the input size
1425 * and the output size
1426 * @input: the input texture
1427 * @target: the output texture
1428 * @shader: the shader to use.
1430 * Transforms @input into @output using @shader on FBO. @resize should
1431 * only ever be %TRUE whenever @input is the input texture of @filter.
1433 * See also: gst_gl_filter_render_to_target()
1435 /* attach target to a FBO, use shader, pass input as "tex" uniform to
1436 * the shader, render input to a quad */
1438 gst_gl_filter_render_to_target_with_shader (GstGLFilter * filter,
1439 gboolean resize, GLuint input, GLuint target, GstGLShader * shader)
1441 filter->default_shader = shader;
1442 _get_attributes (filter);
1444 gst_gl_filter_render_to_target (filter, resize, input, target,
1445 _draw_with_shader_cb, filter);
1449 static const GLfloat vertices[] = {
1450 -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1451 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1452 1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1453 -1.0f, 1.0f, 0.0f, 0.0f, 1.0f
1458 _bind_buffer (GstGLFilter * filter)
1460 const GstGLFuncs *gl = filter->context->gl_vtable;
1462 gl->BindBuffer (GL_ARRAY_BUFFER, filter->vertex_buffer);
1464 _get_attributes (filter);
1465 /* Load the vertex position */
1466 gl->VertexAttribPointer (filter->draw_attr_position_loc, 3, GL_FLOAT,
1467 GL_FALSE, 5 * sizeof (GLfloat), (void *) 0);
1469 /* Load the texture coordinate */
1470 gl->VertexAttribPointer (filter->draw_attr_texture_loc, 2, GL_FLOAT, GL_FALSE,
1471 5 * sizeof (GLfloat), (void *) (3 * sizeof (GLfloat)));
1474 gl->EnableVertexAttribArray (filter->draw_attr_position_loc);
1475 gl->EnableVertexAttribArray (filter->draw_attr_texture_loc);
1479 _unbind_buffer (GstGLFilter * filter)
1481 const GstGLFuncs *gl = filter->context->gl_vtable;
1483 gl->BindBuffer (GL_ARRAY_BUFFER, 0);
1485 gl->DisableVertexAttribArray (filter->draw_attr_position_loc);
1486 gl->DisableVertexAttribArray (filter->draw_attr_texture_loc);
1490 * gst_gl_filter_draw_texture:
1491 * @filter: a #GstGLFilter
1492 * @texture: the texture to draw
1493 * @width: width of @texture
1494 * @height: height of texture
1496 * Draws @texture into the OpenGL scene at the specified @width and @height.
1499 gst_gl_filter_draw_texture (GstGLFilter * filter, GLuint texture,
1500 guint width, guint height)
1502 GstGLContext *context = filter->context;
1503 GstGLFuncs *gl = context->gl_vtable;
1505 GST_DEBUG ("drawing texture:%u dimensions:%ux%u", texture, width, height);
1507 #if GST_GL_HAVE_OPENGL
1508 if (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL) {
1509 GLfloat verts[] = { -1.0f, -1.0f,
1514 GLfloat texcoords[] = { 0.0f, 0.0f,
1520 gl->ActiveTexture (GL_TEXTURE0);
1522 gl->Enable (GL_TEXTURE_2D);
1523 gl->BindTexture (GL_TEXTURE_2D, texture);
1525 gl->ClientActiveTexture (GL_TEXTURE0);
1527 gl->EnableClientState (GL_VERTEX_ARRAY);
1528 gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
1530 gl->VertexPointer (2, GL_FLOAT, 0, &verts);
1531 gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords);
1533 gl->DrawArrays (GL_TRIANGLE_FAN, 0, 4);
1535 gl->DisableClientState (GL_VERTEX_ARRAY);
1536 gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);
1539 if (gst_gl_context_get_gl_api (context) & (GST_GL_API_GLES2 |
1540 GST_GL_API_OPENGL3)) {
1541 GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
1543 if (!filter->vertex_buffer) {
1544 if (gl->GenVertexArrays) {
1545 gl->GenVertexArrays (1, &filter->vao);
1546 gl->BindVertexArray (filter->vao);
1549 gl->GenBuffers (1, &filter->vertex_buffer);
1550 gl->BindBuffer (GL_ARRAY_BUFFER, filter->vertex_buffer);
1551 gl->BufferData (GL_ARRAY_BUFFER, 4 * 5 * sizeof (GLfloat), vertices,
1554 if (gl->GenVertexArrays) {
1555 _bind_buffer (filter);
1556 gl->BindBuffer (GL_ARRAY_BUFFER, 0);
1560 if (gl->GenVertexArrays)
1561 gl->BindVertexArray (filter->vao);
1563 _bind_buffer (filter);
1565 gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
1567 if (gl->GenVertexArrays)
1568 gl->BindVertexArray (0);
1570 _unbind_buffer (filter);