glvideomixer: don't upload if alpha <= 0
[platform/upstream/gstreamer.git] / ext / gl / gstglmixer.c
1 /* Generic video mixer plugin
2  *
3  * GStreamer
4  * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <gst/gst.h>
27 #include <gst/base/gstcollectpads.h>
28 #include <gst/video/video.h>
29
30 #ifdef HAVE_STDLIB_H
31 #include <stdlib.h>
32 #endif
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #endif
36
37 #include "gstglmixer.h"
38
39 #if GST_GL_HAVE_PLATFORM_EGL
40 #include <gst/gl/egl/gsteglimagememory.h>
41 #endif
42
43 #define gst_gl_mixer_parent_class parent_class
44 G_DEFINE_ABSTRACT_TYPE (GstGLMixer, gst_gl_mixer, GST_TYPE_VIDEO_AGGREGATOR);
45 static gboolean gst_gl_mixer_do_bufferpool (GstGLMixer * mix,
46     GstCaps * outcaps);
47
48
49 #define GST_CAT_DEFAULT gst_gl_mixer_debug
50 GST_DEBUG_CATEGORY (gst_gl_mixer_debug);
51
52 static void gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
53     GValue * value, GParamSpec * pspec);
54 static void gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
55     const GValue * value, GParamSpec * pspec);
56 static void gst_gl_mixer_pad_finalize (GObject * object);
57 static GstBuffer *_default_pad_upload_buffer (GstGLMixer * mix,
58     GstGLMixerFrameData * frame, GstBuffer * buffer);
59
60 static void gst_gl_mixer_set_context (GstElement * element,
61     GstContext * context);
62
63 enum
64 {
65   PROP_PAD_0
66 };
67
68 #define GST_GL_MIXER_GET_PRIVATE(obj)  \
69     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_GL_MIXER, GstGLMixerPrivate))
70
71 struct _GstGLMixerPrivate
72 {
73   gboolean negotiated;
74
75   GstBufferPool *pool;
76   gboolean pool_active;
77   GstAllocator *allocator;
78   GstAllocationParams params;
79   GstQuery *query;
80
81   gboolean gl_resource_ready;
82   GMutex gl_resource_lock;
83   GCond gl_resource_cond;
84 };
85
86 G_DEFINE_TYPE (GstGLMixerPad, gst_gl_mixer_pad, GST_TYPE_VIDEO_AGGREGATOR_PAD);
87
88 static void
89 gst_gl_mixer_pad_class_init (GstGLMixerPadClass * klass)
90 {
91   GObjectClass *gobject_class = (GObjectClass *) klass;
92   GstVideoAggregatorPadClass *vaggpad_class =
93       (GstVideoAggregatorPadClass *) klass;
94
95   gobject_class->set_property = gst_gl_mixer_pad_set_property;
96   gobject_class->get_property = gst_gl_mixer_pad_get_property;
97
98   gobject_class->finalize = gst_gl_mixer_pad_finalize;
99
100   vaggpad_class->set_info = NULL;
101   vaggpad_class->prepare_frame = NULL;
102   vaggpad_class->clean_frame = NULL;
103
104   klass->upload_buffer = _default_pad_upload_buffer;
105 }
106
107 static void
108 gst_gl_mixer_pad_finalize (GObject * object)
109 {
110   GstGLMixerPad *pad = GST_GL_MIXER_PAD (object);
111
112   if (pad->upload) {
113     gst_object_unref (pad->upload);
114     pad->upload = NULL;
115   }
116
117   G_OBJECT_CLASS (gst_gl_mixer_pad_parent_class)->finalize (object);
118 }
119
120 static void
121 gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
122     GValue * value, GParamSpec * pspec)
123 {
124   switch (prop_id) {
125     default:
126       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
127       break;
128   }
129 }
130
131 static void
132 gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
133     const GValue * value, GParamSpec * pspec)
134 {
135   switch (prop_id) {
136     default:
137       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
138       break;
139   }
140 }
141
142 static gboolean
143 _negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps)
144 {
145   GstGLMixer *mix = GST_GL_MIXER (vagg);
146   gboolean ret = gst_gl_mixer_do_bufferpool (mix, caps);
147
148   mix->priv->negotiated = ret;
149
150   gst_caps_replace (&mix->out_caps, caps);
151
152   return ret;
153 }
154
155 static gboolean
156 gst_gl_mixer_propose_allocation (GstGLMixer * mix,
157     GstQuery * decide_query, GstQuery * query)
158 {
159   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
160   GstBufferPool *pool;
161   GstStructure *config;
162   GstCaps *caps;
163   guint size = 0;
164   gboolean need_pool;
165   GError *error = NULL;
166   GstStructure *gl_context;
167   gchar *platform, *gl_apis;
168   gpointer handle;
169   GstAllocator *allocator = NULL;
170   GstAllocationParams params;
171
172   gst_query_parse_allocation (query, &caps, &need_pool);
173
174   if (caps == NULL)
175     goto no_caps;
176
177   if ((pool = mix->priv->pool))
178     gst_object_ref (pool);
179
180   if (pool != NULL) {
181     GstCaps *pcaps;
182
183     /* we had a pool, check caps */
184     GST_DEBUG_OBJECT (mix, "check existing pool caps");
185     config = gst_buffer_pool_get_config (pool);
186     gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
187
188     if (!gst_caps_is_equal (caps, pcaps)) {
189       GST_DEBUG_OBJECT (mix, "pool has different caps");
190       /* different caps, we can't use this pool */
191       gst_object_unref (pool);
192       pool = NULL;
193     }
194     gst_structure_free (config);
195   }
196
197   if (!gst_gl_ensure_element_data (mix, &mix->display, &mix->other_context))
198     return FALSE;
199
200   gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
201
202   if (!mix->context) {
203     mix->context = gst_gl_context_new (mix->display);
204     if (!gst_gl_context_create (mix->context, mix->other_context, &error))
205       goto context_error;
206   }
207
208   if (pool == NULL && need_pool) {
209     GstVideoInfo info;
210
211     if (!gst_video_info_from_caps (&info, caps))
212       goto invalid_caps;
213
214     GST_DEBUG_OBJECT (mix, "create new pool");
215     pool = gst_gl_buffer_pool_new (mix->context);
216
217     /* the normal size of a frame */
218     size = info.size;
219
220     config = gst_buffer_pool_get_config (pool);
221     gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
222     if (!gst_buffer_pool_set_config (pool, config))
223       goto config_failed;
224   }
225
226   if (pool) {
227     gst_query_add_allocation_pool (query, pool, size, 1, 0);
228     gst_object_unref (pool);
229   }
230
231   /* we also support various metadata */
232   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
233   if (mix->context->gl_vtable->FenceSync)
234     gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
235
236   gl_apis = gst_gl_api_to_string (gst_gl_context_get_gl_api (mix->context));
237   platform =
238       gst_gl_platform_to_string (gst_gl_context_get_gl_platform (mix->context));
239   handle = (gpointer) gst_gl_context_get_gl_context (mix->context);
240
241   gl_context =
242       gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext",
243       GST_GL_TYPE_CONTEXT, mix->context, "gst.gl.context.handle",
244       G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform,
245       "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
246   gst_query_add_allocation_meta (query,
247       GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context);
248
249   g_free (gl_apis);
250   g_free (platform);
251   gst_structure_free (gl_context);
252
253   gst_allocation_params_init (&params);
254
255   allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR);
256   gst_query_add_allocation_param (query, allocator, &params);
257   gst_object_unref (allocator);
258
259   return TRUE;
260
261   /* ERRORS */
262 no_caps:
263   {
264     GST_DEBUG_OBJECT (mix, "no caps specified");
265     return FALSE;
266   }
267 invalid_caps:
268   {
269     GST_DEBUG_OBJECT (mix, "invalid caps specified");
270     return FALSE;
271   }
272 config_failed:
273   {
274     GST_DEBUG_OBJECT (mix, "failed setting config");
275     return FALSE;
276   }
277 context_error:
278   {
279     GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
280         (NULL));
281     return FALSE;
282   }
283 }
284
285 static gboolean
286 gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix,
287     GstCaps * caps)
288 {
289   gboolean ret;
290   GstCaps *template_caps;
291
292   GST_DEBUG_OBJECT (pad, "try accept caps of %" GST_PTR_FORMAT, caps);
293
294   template_caps = gst_pad_get_pad_template_caps (pad);
295   template_caps = gst_caps_make_writable (template_caps);
296
297   ret = gst_caps_can_intersect (caps, template_caps);
298   GST_DEBUG_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT,
299       (ret ? "" : "not "), caps);
300   gst_caps_unref (template_caps);
301
302   return ret;
303 }
304
305 static GstCaps *
306 gst_gl_mixer_set_caps_features (const GstCaps * caps,
307     const gchar * feature_name)
308 {
309   GstCaps *tmp = gst_caps_copy (caps);
310   guint n = gst_caps_get_size (tmp);
311   guint i = 0;
312
313   for (i = 0; i < n; i++) {
314     GstCapsFeatures *features = gst_caps_get_features (tmp, i);
315     if (features) {
316       guint n_f = gst_caps_features_get_size (features);
317       guint j = 0;
318       for (j = 0; j < n_f; j++) {
319         gst_caps_features_remove_id (features,
320             gst_caps_features_get_nth_id (features, j));
321       }
322     }
323
324     gst_caps_features_add (features, feature_name);
325     gst_caps_set_simple (tmp, "format", G_TYPE_STRING, "RGBA", NULL);
326   }
327
328   return tmp;
329 }
330
331 /* copies the given caps */
332 static GstCaps *
333 gst_gl_mixer_caps_remove_format_info (GstCaps * caps)
334 {
335   GstStructure *st;
336   GstCapsFeatures *f;
337   gint i, n;
338   GstCaps *res;
339
340   res = gst_caps_new_empty ();
341
342   n = gst_caps_get_size (caps);
343   for (i = 0; i < n; i++) {
344     st = gst_caps_get_structure (caps, i);
345     f = gst_caps_get_features (caps, i);
346
347     /* If this is already expressed by the existing caps
348      * skip this structure */
349     if (i > 0 && gst_caps_is_subset_structure_full (res, st, f))
350       continue;
351
352     st = gst_structure_copy (st);
353     /* Only remove format info for the cases when we can actually convert */
354     if (!gst_caps_features_is_any (f)
355         && gst_caps_features_is_equal (f,
356             GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY))
357       gst_structure_remove_fields (st, "format", "colorimetry", "chroma-site",
358           NULL);
359     gst_structure_remove_fields (st, "width", "height", NULL);
360
361     gst_caps_append_structure_full (res, st, gst_caps_features_copy (f));
362   }
363
364   return res;
365 }
366
367 GstCaps *
368 gst_gl_mixer_update_caps (GstGLMixer * mix, GstCaps * caps)
369 {
370   GstCaps *result = NULL;
371   GstCaps *glcaps = gst_gl_mixer_set_caps_features (caps,
372       GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
373 #if GST_GL_HAVE_PLATFORM_EGL
374   GstCaps *eglcaps = gst_gl_mixer_set_caps_features (caps,
375       GST_CAPS_FEATURE_MEMORY_EGL_IMAGE);
376 #endif
377   GstCaps *uploadcaps = gst_gl_mixer_set_caps_features (caps,
378       GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META);
379   GstCaps *raw_caps =
380       gst_caps_from_string (GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS));
381
382   result = gst_caps_new_empty ();
383
384   result = gst_caps_merge (result, glcaps);
385 #if GST_GL_HAVE_PLATFORM_EGL
386   result = gst_caps_merge (result, eglcaps);
387 #endif
388   result = gst_caps_merge (result, uploadcaps);
389   result = gst_caps_merge (result, raw_caps);
390
391   result = gst_caps_merge (result, gst_gl_mixer_caps_remove_format_info (caps));
392
393   GST_DEBUG_OBJECT (mix, "returning %" GST_PTR_FORMAT, result);
394
395   return result;
396 }
397
398 static GstCaps *
399 gst_gl_mixer_pad_sink_getcaps (GstPad * pad, GstGLMixer * mix, GstCaps * filter)
400 {
401   GstCaps *srccaps;
402   GstCaps *template_caps;
403   GstCaps *filtered_caps;
404   GstCaps *returned_caps;
405   gboolean had_current_caps = TRUE;
406
407   template_caps = gst_pad_get_pad_template_caps (pad);
408
409   srccaps = gst_pad_get_current_caps (pad);
410   if (srccaps == NULL) {
411     had_current_caps = FALSE;
412     srccaps = template_caps;
413   } else {
414     srccaps = gst_caps_merge (srccaps, gst_gl_mixer_update_caps (mix, srccaps));
415   }
416
417   filtered_caps = srccaps;
418   if (filter)
419     filtered_caps = gst_caps_intersect (srccaps, filter);
420   returned_caps = gst_caps_intersect (filtered_caps, template_caps);
421
422   if (filter)
423     gst_caps_unref (filtered_caps);
424   if (had_current_caps)
425     gst_caps_unref (template_caps);
426
427   GST_DEBUG_OBJECT (pad, "returning %" GST_PTR_FORMAT, returned_caps);
428
429   return returned_caps;
430 }
431
432 static gboolean
433 gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
434     GstQuery * query)
435 {
436   gboolean ret = FALSE;
437   GstGLMixer *mix = GST_GL_MIXER (agg);
438   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
439
440   GST_TRACE ("QUERY %" GST_PTR_FORMAT, query);
441
442   switch (GST_QUERY_TYPE (query)) {
443     case GST_QUERY_CAPS:
444     {
445       GstCaps *filter, *caps;
446
447       gst_query_parse_caps (query, &filter);
448       caps = gst_gl_mixer_pad_sink_getcaps (GST_PAD (bpad), mix, filter);
449       gst_query_set_caps_result (query, caps);
450       gst_caps_unref (caps);
451       ret = TRUE;
452       break;
453     }
454     case GST_QUERY_ACCEPT_CAPS:
455     {
456       GstCaps *caps;
457
458       gst_query_parse_accept_caps (query, &caps);
459       ret = gst_gl_mixer_pad_sink_acceptcaps (GST_PAD (bpad), mix, caps);
460       gst_query_set_accept_caps_result (query, ret);
461       ret = TRUE;
462       break;
463     }
464     case GST_QUERY_ALLOCATION:
465     {
466       GstQuery *decide_query = NULL;
467
468       GST_OBJECT_LOCK (mix);
469       if (G_UNLIKELY (!mix->priv->negotiated)) {
470         GST_DEBUG_OBJECT (mix,
471             "not negotiated yet, can't answer ALLOCATION query");
472         GST_OBJECT_UNLOCK (mix);
473         return FALSE;
474       }
475       if ((decide_query = mix->priv->query))
476         gst_query_ref (decide_query);
477       GST_OBJECT_UNLOCK (mix);
478
479       GST_DEBUG_OBJECT (mix,
480           "calling propose allocation with query %" GST_PTR_FORMAT,
481           decide_query);
482
483       /* pass the query to the propose_allocation vmethod if any */
484       ret = gst_gl_mixer_propose_allocation (mix, decide_query, query);
485
486       if (decide_query)
487         gst_query_unref (decide_query);
488
489       GST_DEBUG_OBJECT (mix, "ALLOCATION ret %d, %" GST_PTR_FORMAT, ret, query);
490       break;
491     }
492     case GST_QUERY_CONTEXT:
493     {
494       ret = gst_gl_handle_context_query ((GstElement *) mix, query,
495           &mix->display, &mix->other_context);
496       if (mix->display)
497         gst_gl_display_filter_gl_api (mix->display,
498             mix_class->supported_gl_api);
499       break;
500     }
501     default:
502       ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);
503       break;
504   }
505
506   return ret;
507 }
508
509 static void
510 gst_gl_mixer_pad_init (GstGLMixerPad * mixerpad)
511 {
512 }
513
514 /* GLMixer signals and args */
515 enum
516 {
517   /* FILL ME */
518   LAST_SIGNAL
519 };
520
521 enum
522 {
523   PROP_0,
524   PROP_CONTEXT
525 };
526
527 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
528     GST_PAD_SRC,
529     GST_PAD_ALWAYS,
530     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
531         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
532             "RGBA") "; "
533         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
534         (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
535             "RGBA")
536         "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
537     );
538
539 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
540     GST_PAD_SINK,
541     GST_PAD_REQUEST,
542     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
543         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
544             "RGBA") "; "
545         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
546         (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
547             "RGBA")
548         "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
549     );
550
551 static gboolean gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query);
552 static GstFlowReturn
553 gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator,
554     GstBuffer ** outbuf);
555 static gboolean
556 gst_gl_mixer_src_activate_mode (GstAggregator * aggregator, GstPadMode mode,
557     gboolean active);
558 static gboolean gst_gl_mixer_stop (GstAggregator * agg);
559 static gboolean gst_gl_mixer_start (GstAggregator * agg);
560
561 static GstFlowReturn
562 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg,
563     GstBuffer * outbuffer);
564
565 static void gst_gl_mixer_set_property (GObject * object, guint prop_id,
566     const GValue * value, GParamSpec * pspec);
567 static void gst_gl_mixer_get_property (GObject * object, guint prop_id,
568     GValue * value, GParamSpec * pspec);
569
570 static gboolean gst_gl_mixer_decide_allocation (GstGLMixer * mix,
571     GstQuery * query);
572 static gboolean gst_gl_mixer_set_allocation (GstGLMixer * mix,
573     GstBufferPool * pool, GstAllocator * allocator,
574     GstAllocationParams * params, GstQuery * query);
575
576 static void gst_gl_mixer_finalize (GObject * object);
577
578 static void
579 gst_gl_mixer_class_init (GstGLMixerClass * klass)
580 {
581   GObjectClass *gobject_class;
582   GstElementClass *element_class;
583
584   GstVideoAggregatorClass *videoaggregator_class =
585       (GstVideoAggregatorClass *) klass;
586   GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
587
588   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "opengl mixer");
589
590   gobject_class = (GObjectClass *) klass;
591   element_class = GST_ELEMENT_CLASS (klass);
592
593   g_type_class_add_private (klass, sizeof (GstGLMixerPrivate));
594
595   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gl_mixer_finalize);
596
597   gobject_class->get_property = gst_gl_mixer_get_property;
598   gobject_class->set_property = gst_gl_mixer_set_property;
599
600   gst_element_class_add_pad_template (element_class,
601       gst_static_pad_template_get (&src_factory));
602   gst_element_class_add_pad_template (element_class,
603       gst_static_pad_template_get (&sink_factory));
604
605   element_class->set_context = GST_DEBUG_FUNCPTR (gst_gl_mixer_set_context);
606
607   agg_class->sinkpads_type = GST_TYPE_GL_MIXER_PAD;
608   agg_class->sink_query = gst_gl_mixer_sink_query;
609   agg_class->src_query = gst_gl_mixer_src_query;
610   agg_class->src_activate = gst_gl_mixer_src_activate_mode;
611   agg_class->stop = gst_gl_mixer_stop;
612   agg_class->start = gst_gl_mixer_start;
613
614   videoaggregator_class->aggregate_frames = gst_gl_mixer_aggregate_frames;
615   videoaggregator_class->get_output_buffer = gst_gl_mixer_get_output_buffer;
616   videoaggregator_class->negotiated_caps = _negotiated_caps;
617   videoaggregator_class->find_best_format = NULL;
618
619   g_object_class_install_property (gobject_class, PROP_CONTEXT,
620       g_param_spec_object ("context",
621           "OpenGL context",
622           "Get OpenGL context",
623           GST_GL_TYPE_CONTEXT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
624
625   /* Register the pad class */
626   g_type_class_ref (GST_TYPE_GL_MIXER_PAD);
627
628   klass->set_caps = NULL;
629   klass->supported_gl_api = GST_GL_API_ANY;
630 }
631
632 static void
633 gst_gl_mixer_reset (GstGLMixer * mix)
634 {
635   /* clean up collect data */
636   mix->priv->negotiated = FALSE;
637 }
638
639 static void
640 gst_gl_mixer_init (GstGLMixer * mix)
641 {
642   mix->priv = GST_GL_MIXER_GET_PRIVATE (mix);
643   mix->array_buffers = 0;
644   mix->display = NULL;
645   mix->fbo = 0;
646   mix->depthbuffer = 0;
647
648   mix->priv->gl_resource_ready = FALSE;
649   g_mutex_init (&mix->priv->gl_resource_lock);
650   g_cond_init (&mix->priv->gl_resource_cond);
651   /* initialize variables */
652   gst_gl_mixer_reset (mix);
653 }
654
655 static void
656 gst_gl_mixer_finalize (GObject * object)
657 {
658   GstGLMixer *mix = GST_GL_MIXER (object);
659   GstGLMixerPrivate *priv = mix->priv;
660
661   if (mix->other_context) {
662     gst_object_unref (mix->other_context);
663     mix->other_context = NULL;
664   }
665
666   g_mutex_clear (&priv->gl_resource_lock);
667   g_cond_clear (&priv->gl_resource_cond);
668   G_OBJECT_CLASS (parent_class)->finalize (object);
669 }
670
671 static void
672 gst_gl_mixer_set_context (GstElement * element, GstContext * context)
673 {
674   GstGLMixer *mix = GST_GL_MIXER (element);
675   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
676
677   gst_gl_handle_set_context (element, context, &mix->display,
678       &mix->other_context);
679
680   if (mix->display)
681     gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
682 }
683
684 static gboolean
685 gst_gl_mixer_activate (GstGLMixer * mix, gboolean active)
686 {
687   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
688   gboolean result = TRUE;
689
690   if (active) {
691     if (!gst_gl_ensure_element_data (mix, &mix->display, &mix->other_context))
692       return FALSE;
693
694     gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
695   }
696
697   return result;
698 }
699
700 static gboolean
701 gst_gl_mixer_src_activate_mode (GstAggregator * aggregator, GstPadMode mode,
702     gboolean active)
703 {
704   GstGLMixer *mix;
705   gboolean result = FALSE;
706
707   mix = GST_GL_MIXER (aggregator);
708
709   switch (mode) {
710     case GST_PAD_MODE_PUSH:
711     case GST_PAD_MODE_PULL:
712       result = gst_gl_mixer_activate (mix, active);
713       break;
714     default:
715       result = TRUE;
716       break;
717   }
718   return result;
719 }
720
721 static gboolean
722 gst_gl_mixer_query_caps (GstPad * pad, GstAggregator * agg, GstQuery * query)
723 {
724   GstCaps *filter, *current_caps, *retcaps;
725
726   gst_query_parse_caps (query, &filter);
727
728   current_caps = gst_pad_get_current_caps (pad);
729   if (current_caps == NULL)
730     current_caps = gst_pad_get_pad_template_caps (agg->srcpad);
731
732   retcaps = gst_gl_mixer_caps_remove_format_info (current_caps);
733   gst_caps_unref (current_caps);
734
735   if (filter)
736     retcaps =
737         gst_caps_intersect_full (filter, retcaps, GST_CAPS_INTERSECT_FIRST);
738
739   gst_query_set_caps_result (query, retcaps);
740   gst_caps_unref (retcaps);
741
742   return TRUE;
743 }
744
745 static gboolean
746 gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query)
747 {
748   gboolean res = FALSE;
749   GstGLMixer *mix = GST_GL_MIXER (agg);
750   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
751
752   switch (GST_QUERY_TYPE (query)) {
753     case GST_QUERY_CONTEXT:
754     {
755       res = gst_gl_handle_context_query ((GstElement *) mix, query,
756           &mix->display, &mix->other_context);
757       if (mix->display)
758         gst_gl_display_filter_gl_api (mix->display,
759             mix_class->supported_gl_api);
760       break;
761     }
762     case GST_QUERY_CAPS:
763       res = gst_gl_mixer_query_caps (agg->srcpad, agg, query);
764       break;
765     default:
766       res = GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
767       break;
768   }
769
770   return res;
771 }
772
773 static GstFlowReturn
774 gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator,
775     GstBuffer ** outbuf)
776 {
777   GstGLMixer *mix = GST_GL_MIXER (videoaggregator);
778
779   if (!mix->priv->pool_active) {
780     if (!gst_buffer_pool_set_active (mix->priv->pool, TRUE)) {
781       GST_ELEMENT_ERROR (mix, RESOURCE, SETTINGS,
782           ("failed to activate bufferpool"), ("failed to activate bufferpool"));
783       return GST_FLOW_ERROR;
784     }
785     mix->priv->pool_active = TRUE;
786   }
787
788   return gst_buffer_pool_acquire_buffer (mix->priv->pool, outbuf, NULL);
789 }
790
791 static gboolean
792 gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query)
793 {
794   GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
795   GstBufferPool *pool = NULL;
796   GstStructure *config;
797   GstCaps *caps;
798   guint min, max, size;
799   gboolean update_pool;
800   GError *error = NULL;
801   guint idx;
802   guint out_width, out_height;
803   GstGLContext *other_context = NULL;
804   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
805   gboolean same_downstream_gl_context = FALSE;
806
807   if (!gst_gl_ensure_element_data (mix, &mix->display, &mix->other_context))
808     return FALSE;
809
810   gst_gl_display_filter_gl_api (mix->display, mixer_class->supported_gl_api);
811
812   if (gst_query_find_allocation_meta (query,
813           GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) {
814     GstGLContext *context;
815     const GstStructure *upload_meta_params;
816     gpointer handle;
817     gchar *type;
818     gchar *apis;
819
820     gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params);
821     if (upload_meta_params) {
822       if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext",
823               GST_GL_TYPE_CONTEXT, &context, NULL) && context) {
824         GstGLContext *old = mix->context;
825
826         mix->context = context;
827         if (old)
828           gst_object_unref (old);
829         same_downstream_gl_context = TRUE;
830       } else if (gst_structure_get (upload_meta_params, "gst.gl.context.handle",
831               G_TYPE_POINTER, &handle, "gst.gl.context.type", G_TYPE_STRING,
832               &type, "gst.gl.context.apis", G_TYPE_STRING, &apis, NULL)
833           && handle) {
834         GstGLPlatform platform;
835         GstGLAPI gl_apis;
836
837         GST_DEBUG ("got GL context handle 0x%p with type %s and apis %s",
838             handle, type, apis);
839
840         platform = gst_gl_platform_from_string (type);
841         gl_apis = gst_gl_api_from_string (apis);
842
843         if (gl_apis && platform)
844           other_context =
845               gst_gl_context_new_wrapped (mix->display, (guintptr) handle,
846               platform, gl_apis);
847       }
848     }
849   }
850
851   if (mix->other_context) {
852     if (!other_context) {
853       other_context = mix->other_context;
854     } else {
855       GST_ELEMENT_WARNING (mix, LIBRARY, SETTINGS,
856           ("%s", "Cannot share with more than one GL context"),
857           ("%s", "Cannot share with more than one GL context"));
858     }
859   }
860
861   if (!mix->context) {
862     mix->context = gst_gl_context_new (mix->display);
863     if (!gst_gl_context_create (mix->context, other_context, &error))
864       goto context_error;
865   }
866
867   out_width = GST_VIDEO_INFO_WIDTH (&vagg->info);
868   out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info);
869
870   g_mutex_lock (&mix->priv->gl_resource_lock);
871   mix->priv->gl_resource_ready = FALSE;
872   if (mix->fbo) {
873     gst_gl_context_del_fbo (mix->context, mix->fbo, mix->depthbuffer);
874     mix->fbo = 0;
875     mix->depthbuffer = 0;
876   }
877
878   if (!gst_gl_context_gen_fbo (mix->context, out_width, out_height,
879           &mix->fbo, &mix->depthbuffer)) {
880     g_cond_signal (&mix->priv->gl_resource_cond);
881     g_mutex_unlock (&mix->priv->gl_resource_lock);
882     goto context_error;
883   }
884
885   if (mix->out_tex_id)
886     gst_gl_context_del_texture (mix->context, &mix->out_tex_id);
887   gst_gl_context_gen_texture (mix->context, &mix->out_tex_id,
888       GST_VIDEO_FORMAT_RGBA, out_width, out_height);
889
890   gst_query_parse_allocation (query, &caps, NULL);
891
892   if (mixer_class->set_caps)
893     mixer_class->set_caps (mix, caps);
894
895   mix->priv->gl_resource_ready = TRUE;
896   g_cond_signal (&mix->priv->gl_resource_cond);
897   g_mutex_unlock (&mix->priv->gl_resource_lock);
898
899   if (gst_query_get_n_allocation_pools (query) > 0) {
900     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
901
902     update_pool = TRUE;
903   } else {
904     GstVideoInfo vinfo;
905
906     gst_video_info_init (&vinfo);
907     gst_video_info_from_caps (&vinfo, caps);
908     size = vinfo.size;
909     min = max = 0;
910     update_pool = FALSE;
911   }
912
913   if (!pool || (!same_downstream_gl_context
914           && gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE,
915               NULL)
916           && !gst_buffer_pool_has_option (pool,
917               GST_BUFFER_POOL_OPTION_GL_SYNC_META))) {
918     /* can't use this pool */
919     if (pool)
920       gst_object_unref (pool);
921     pool = gst_gl_buffer_pool_new (mix->context);
922   }
923   config = gst_buffer_pool_get_config (pool);
924
925   gst_buffer_pool_config_set_params (config, caps, size, min, max);
926   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
927   if (gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL))
928     gst_buffer_pool_config_add_option (config,
929         GST_BUFFER_POOL_OPTION_GL_SYNC_META);
930   gst_buffer_pool_config_add_option (config,
931       GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
932
933   gst_buffer_pool_set_config (pool, config);
934
935   if (update_pool)
936     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
937   else
938     gst_query_add_allocation_pool (query, pool, size, min, max);
939
940   gst_object_unref (pool);
941
942   return TRUE;
943
944 context_error:
945   {
946     GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
947         (NULL));
948     return FALSE;
949   }
950 }
951
952 /* takes ownership of the pool, allocator and query */
953 static gboolean
954 gst_gl_mixer_set_allocation (GstGLMixer * mix,
955     GstBufferPool * pool, GstAllocator * allocator,
956     GstAllocationParams * params, GstQuery * query)
957 {
958   GstAllocator *oldalloc;
959   GstBufferPool *oldpool;
960   GstQuery *oldquery;
961   GstGLMixerPrivate *priv = mix->priv;
962
963   GST_DEBUG ("storing allocation query");
964
965   GST_OBJECT_LOCK (mix);
966   oldpool = priv->pool;
967   priv->pool = pool;
968   priv->pool_active = FALSE;
969
970   oldalloc = priv->allocator;
971   priv->allocator = allocator;
972
973   oldquery = priv->query;
974   priv->query = query;
975
976   if (params)
977     priv->params = *params;
978   else
979     gst_allocation_params_init (&priv->params);
980   GST_OBJECT_UNLOCK (mix);
981
982   if (oldpool) {
983     GST_DEBUG_OBJECT (mix, "deactivating old pool %p", oldpool);
984     gst_buffer_pool_set_active (oldpool, FALSE);
985     gst_object_unref (oldpool);
986   }
987   if (oldalloc) {
988     gst_object_unref (oldalloc);
989   }
990   if (oldquery) {
991     gst_query_unref (oldquery);
992   }
993   return TRUE;
994 }
995
996 static gboolean
997 gst_gl_mixer_do_bufferpool (GstGLMixer * mix, GstCaps * outcaps)
998 {
999   GstQuery *query;
1000   gboolean result = TRUE;
1001   GstBufferPool *pool = NULL;
1002   GstAllocator *allocator;
1003   GstAllocationParams params;
1004   GstAggregator *agg = GST_AGGREGATOR (mix);
1005
1006   /* find a pool for the negotiated caps now */
1007   GST_DEBUG_OBJECT (mix, "doing allocation query");
1008   query = gst_query_new_allocation (outcaps, TRUE);
1009   if (!gst_pad_peer_query (agg->srcpad, query)) {
1010     /* not a problem, just debug a little */
1011     GST_DEBUG_OBJECT (mix, "peer ALLOCATION query failed");
1012   }
1013
1014   GST_DEBUG_OBJECT (mix, "calling decide_allocation");
1015   result = gst_gl_mixer_decide_allocation (mix, query);
1016
1017   GST_DEBUG_OBJECT (mix, "ALLOCATION (%d) params: %" GST_PTR_FORMAT, result,
1018       query);
1019
1020   if (!result)
1021     goto no_decide_allocation;
1022
1023   /* we got configuration from our peer or the decide_allocation method,
1024    * parse them */
1025   if (gst_query_get_n_allocation_params (query) > 0) {
1026     gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
1027   } else {
1028     allocator = NULL;
1029     gst_allocation_params_init (&params);
1030   }
1031
1032   if (gst_query_get_n_allocation_pools (query) > 0)
1033     gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
1034
1035   /* now store */
1036   result = gst_gl_mixer_set_allocation (mix, pool, allocator, &params, query);
1037
1038   return result;
1039
1040   /* Errors */
1041 no_decide_allocation:
1042   {
1043     GST_WARNING_OBJECT (mix, "Failed to decide allocation");
1044     gst_query_unref (query);
1045
1046     return result;
1047   }
1048 }
1049
1050 static GstBuffer *
1051 _default_pad_upload_buffer (GstGLMixer * mix, GstGLMixerFrameData * frame,
1052     GstBuffer * buffer)
1053 {
1054   GstVideoAggregatorPad *vaggpad = GST_VIDEO_AGGREGATOR_PAD (frame->pad);
1055   GstGLMixerPad *pad = frame->pad;
1056   GstBuffer *uploaded_buf, *gl_buffer;
1057   GstCaps *gl_caps;
1058   GstCapsFeatures *gl_features;
1059   GstVideoInfo gl_info;
1060   GstVideoFrame gl_frame;
1061   GstGLSyncMeta *sync_meta;
1062
1063   gst_video_info_set_format (&gl_info,
1064       GST_VIDEO_FORMAT_RGBA,
1065       GST_VIDEO_INFO_WIDTH (&vaggpad->info),
1066       GST_VIDEO_INFO_HEIGHT (&vaggpad->info));
1067   gl_features =
1068       gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
1069
1070   gl_caps = gst_video_info_to_caps (&gl_info);
1071   gst_caps_set_features (gl_caps, 0, gst_caps_features_copy (gl_features));
1072
1073   if (!pad->upload) {
1074     GstCaps *in_caps = gst_pad_get_current_caps (GST_PAD (pad));
1075     GstCaps *upload_caps = gst_caps_copy (in_caps);
1076
1077     pad->upload = gst_gl_upload_new (mix->context);
1078
1079     gst_caps_set_features (upload_caps, 0,
1080         gst_caps_features_copy (gl_features));
1081     gst_gl_upload_set_caps (pad->upload, in_caps, upload_caps);
1082
1083     if (!pad->convert) {
1084       pad->convert = gst_gl_color_convert_new (mix->context);
1085
1086       gst_gl_color_convert_set_caps (pad->convert, upload_caps, gl_caps);
1087     }
1088
1089     gst_caps_unref (upload_caps);
1090     gst_caps_unref (in_caps);
1091   }
1092
1093   gst_caps_features_free (gl_features);
1094   gst_caps_unref (gl_caps);
1095
1096   sync_meta = gst_buffer_get_gl_sync_meta (vaggpad->buffer);
1097   if (sync_meta)
1098     gst_gl_sync_meta_wait (sync_meta);
1099
1100   if (gst_gl_upload_perform_with_buffer (pad->upload,
1101           vaggpad->buffer, &uploaded_buf) != GST_GL_UPLOAD_DONE) {
1102     return NULL;
1103   }
1104
1105   if (!(gl_buffer = gst_gl_color_convert_perform (pad->convert, uploaded_buf))) {
1106     gst_buffer_unref (uploaded_buf);
1107     return NULL;
1108   }
1109
1110   if (!gst_video_frame_map (&gl_frame, &gl_info, gl_buffer,
1111           GST_MAP_READ | GST_MAP_GL)) {
1112     gst_buffer_unref (uploaded_buf);
1113     gst_buffer_unref (gl_buffer);
1114     return NULL;
1115   }
1116
1117   frame->texture = *(guint *) gl_frame.data[0];
1118
1119   gst_buffer_unref (uploaded_buf);
1120   gst_video_frame_unmap (&gl_frame);
1121
1122   return gl_buffer;
1123 }
1124
1125 gboolean
1126 gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
1127 {
1128   guint i;
1129   GList *walk;
1130   guint out_tex;
1131   gboolean res = TRUE;
1132   guint array_index = 0;
1133   GstVideoFrame out_frame;
1134   GstElement *element = GST_ELEMENT (mix);
1135   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
1136   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
1137   GstGLMixerPrivate *priv = mix->priv;
1138   gboolean to_download =
1139       gst_caps_features_is_equal (GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY,
1140       gst_caps_get_features (mix->out_caps, 0));
1141   GstMapFlags out_map_flags = GST_MAP_WRITE;
1142
1143   GST_TRACE ("Processing buffers");
1144
1145   to_download |= !gst_is_gl_memory (gst_buffer_peek_memory (outbuf, 0));
1146
1147   if (!to_download)
1148     out_map_flags |= GST_MAP_GL;
1149
1150   if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf, out_map_flags)) {
1151     return FALSE;
1152   }
1153
1154   if (!to_download) {
1155     out_tex = *(guint *) out_frame.data[0];
1156   } else {
1157     GST_INFO ("Output Buffer does not contain correct memory, "
1158         "attempting to wrap for download");
1159
1160     if (!mix->download)
1161       mix->download = gst_gl_download_new (mix->context);
1162
1163     gst_gl_download_set_format (mix->download, &out_frame.info);
1164     out_tex = mix->out_tex_id;
1165   }
1166
1167   GST_OBJECT_LOCK (mix);
1168   walk = element->sinkpads;
1169
1170   i = mix->frames->len;
1171   g_ptr_array_set_size (mix->frames, element->numsinkpads);
1172   for (; i < element->numsinkpads; i++)
1173     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
1174   while (walk) {
1175     GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data);
1176     GstGLMixerPadClass *pad_class = GST_GL_MIXER_PAD_GET_CLASS (pad);
1177     GstVideoAggregatorPad *vaggpad = walk->data;
1178     GstGLMixerFrameData *frame;
1179
1180     frame = g_ptr_array_index (mix->frames, array_index);
1181     frame->pad = pad;
1182     frame->texture = 0;
1183
1184     walk = g_list_next (walk);
1185
1186     if (vaggpad->buffer != NULL) {
1187       g_assert (pad_class->upload_buffer);
1188
1189       if (pad->gl_buffer)
1190         gst_buffer_unref (pad->gl_buffer);
1191       pad->gl_buffer = pad_class->upload_buffer (mix, frame, vaggpad->buffer);
1192
1193       GST_DEBUG_OBJECT (pad,
1194           "uploaded buffer %" GST_PTR_FORMAT " from buffer %" GST_PTR_FORMAT,
1195           pad->gl_buffer, vaggpad->buffer);
1196     }
1197
1198     ++array_index;
1199   }
1200
1201   g_mutex_lock (&priv->gl_resource_lock);
1202   if (!priv->gl_resource_ready)
1203     g_cond_wait (&priv->gl_resource_cond, &priv->gl_resource_lock);
1204
1205   if (!priv->gl_resource_ready) {
1206     g_mutex_unlock (&priv->gl_resource_lock);
1207     GST_ERROR_OBJECT (mix,
1208         "fbo used to render can't be created, do not run process_textures");
1209     res = FALSE;
1210     goto out;
1211   }
1212
1213   mix_class->process_textures (mix, mix->frames, out_tex);
1214
1215   g_mutex_unlock (&priv->gl_resource_lock);
1216
1217   if (to_download) {
1218     if (!gst_gl_download_perform_with_data (mix->download, out_tex,
1219             out_frame.data)) {
1220       GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s",
1221               "Failed to download video frame"), (NULL));
1222       res = FALSE;
1223       goto out;
1224     }
1225   }
1226
1227 out:
1228   i = 0;
1229   walk = GST_ELEMENT (mix)->sinkpads;
1230   while (walk) {
1231     GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data);
1232
1233     if (pad->upload)
1234       gst_gl_upload_release_buffer (pad->upload);
1235
1236     walk = g_list_next (walk);
1237     i++;
1238   }
1239   GST_OBJECT_UNLOCK (mix);
1240
1241   gst_video_frame_unmap (&out_frame);
1242
1243   return res;
1244 }
1245
1246 static gboolean
1247 gst_gl_mixer_process_buffers (GstGLMixer * mix, GstBuffer * outbuf)
1248 {
1249   GList *walk;
1250   guint i, array_index = 0;
1251   GstElement *element = GST_ELEMENT (mix);
1252   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
1253
1254   GST_OBJECT_LOCK (mix);
1255   walk = GST_ELEMENT (mix)->sinkpads;
1256   i = mix->frames->len;
1257   g_ptr_array_set_size (mix->frames, element->numsinkpads);
1258   for (; i < element->numsinkpads; i++)
1259     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
1260   while (walk) {                /* We walk with this list because it's ordered */
1261     GstVideoAggregatorPad *vaggpad = walk->data;
1262
1263     walk = g_list_next (walk);
1264
1265     if (vaggpad->buffer != NULL) {
1266       /* put buffer into array */
1267       mix->array_buffers->pdata[array_index] = vaggpad->buffer;
1268     }
1269     ++array_index;
1270   }
1271   GST_OBJECT_UNLOCK (mix);
1272
1273   return mix_class->process_buffers (mix, mix->array_buffers, outbuf);
1274 }
1275
1276
1277
1278 static GstFlowReturn
1279 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
1280 {
1281   gboolean res = FALSE;
1282   GstGLMixer *mix = GST_GL_MIXER (vagg);
1283   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (vagg);
1284   GstGLSyncMeta *sync_meta;
1285
1286   if (mix_class->process_buffers)
1287     res = gst_gl_mixer_process_buffers (mix, outbuf);
1288   else if (mix_class->process_textures)
1289     res = gst_gl_mixer_process_textures (mix, outbuf);
1290
1291   sync_meta = gst_buffer_get_gl_sync_meta (outbuf);
1292   if (sync_meta)
1293     gst_gl_sync_meta_set_sync_point (sync_meta, mix->context);
1294
1295   return res ? GST_FLOW_OK : GST_FLOW_ERROR;
1296 }
1297
1298 static void
1299 gst_gl_mixer_get_property (GObject * object,
1300     guint prop_id, GValue * value, GParamSpec * pspec)
1301 {
1302   GstGLMixer *mixer = GST_GL_MIXER (object);
1303
1304   switch (prop_id) {
1305     case PROP_CONTEXT:
1306       g_value_set_object (value, mixer->context);
1307       break;
1308     default:
1309       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1310       break;
1311   }
1312 }
1313
1314 static void
1315 gst_gl_mixer_set_property (GObject * object,
1316     guint prop_id, const GValue * value, GParamSpec * pspec)
1317 {
1318   switch (prop_id) {
1319     default:
1320       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1321       break;
1322   }
1323 }
1324
1325 static gboolean
1326 _clean_upload (GstAggregator * agg, GstAggregatorPad * aggpad, gpointer udata)
1327 {
1328   GstGLMixerPad *pad = GST_GL_MIXER_PAD (aggpad);
1329
1330   if (pad->gl_buffer) {
1331     gst_buffer_unref (pad->gl_buffer);
1332     pad->gl_buffer = NULL;
1333   }
1334
1335   if (pad->upload) {
1336     gst_object_unref (pad->upload);
1337     pad->upload = NULL;
1338   }
1339
1340   if (pad->convert) {
1341     gst_object_unref (pad->convert);
1342     pad->convert = NULL;
1343   }
1344
1345   return TRUE;
1346 }
1347
1348 static void
1349 _free_glmixer_frame_data (GstGLMixerFrameData * frame)
1350 {
1351   g_slice_free1 (sizeof (GstGLMixerFrameData), frame);
1352 }
1353
1354 static gboolean
1355 gst_gl_mixer_start (GstAggregator * agg)
1356 {
1357   guint i;
1358   GstGLMixer *mix = GST_GL_MIXER (agg);
1359   GstElement *element = GST_ELEMENT (agg);
1360
1361   GST_OBJECT_LOCK (mix);
1362   mix->array_buffers = g_ptr_array_new_full (element->numsinkpads,
1363       (GDestroyNotify) _free_glmixer_frame_data);
1364   mix->frames = g_ptr_array_new_full (element->numsinkpads, NULL);
1365
1366   g_ptr_array_set_size (mix->array_buffers, element->numsinkpads);
1367   g_ptr_array_set_size (mix->frames, element->numsinkpads);
1368
1369   for (i = 0; i < element->numsinkpads; i++)
1370     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
1371
1372   GST_OBJECT_UNLOCK (mix);
1373
1374   return TRUE;
1375 }
1376
1377 static gboolean
1378 gst_gl_mixer_stop (GstAggregator * agg)
1379 {
1380   GstGLMixer *mix = GST_GL_MIXER (agg);
1381   GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
1382
1383   GST_OBJECT_LOCK (agg);
1384   g_ptr_array_free (mix->frames, TRUE);
1385   mix->frames = NULL;
1386   g_ptr_array_free (mix->array_buffers, TRUE);
1387   mix->array_buffers = NULL;
1388   GST_OBJECT_UNLOCK (agg);
1389
1390   if (mixer_class->reset)
1391     mixer_class->reset (mix);
1392   if (mix->fbo) {
1393     gst_gl_context_del_fbo (mix->context, mix->fbo, mix->depthbuffer);
1394     mix->fbo = 0;
1395     mix->depthbuffer = 0;
1396   }
1397   if (mix->download) {
1398     gst_object_unref (mix->download);
1399     mix->download = NULL;
1400   }
1401
1402   gst_aggregator_iterate_sinkpads (GST_AGGREGATOR (mix), _clean_upload, NULL);
1403
1404   if (mix->priv->query) {
1405     gst_query_unref (mix->priv->query);
1406     mix->priv->query = NULL;
1407   }
1408
1409   if (mix->priv->pool) {
1410     gst_object_unref (mix->priv->pool);
1411     mix->priv->pool = NULL;
1412   }
1413
1414   if (mix->display) {
1415     gst_object_unref (mix->display);
1416     mix->display = NULL;
1417   }
1418
1419   if (mix->context) {
1420     gst_object_unref (mix->context);
1421     mix->context = NULL;
1422   }
1423
1424   gst_gl_mixer_reset (mix);
1425
1426   return TRUE;
1427 }