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