1 /* Generic video mixer plugin
4 * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
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.
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.
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.
27 #include <gst/video/video.h>
29 #include "gstglmixer.h"
31 #if GST_GL_HAVE_PLATFORM_EGL
32 #include <gst/gl/egl/gsteglimagememory.h>
35 #define gst_gl_mixer_parent_class parent_class
36 G_DEFINE_ABSTRACT_TYPE (GstGLMixer, gst_gl_mixer, GST_TYPE_GL_BASE_MIXER);
38 #define GST_CAT_DEFAULT gst_gl_mixer_debug
39 GST_DEBUG_CATEGORY (gst_gl_mixer_debug);
41 static void gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
42 GValue * value, GParamSpec * pspec);
43 static void gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
44 const GValue * value, GParamSpec * pspec);
45 static void gst_gl_mixer_pad_finalize (GObject * object);
52 #define GST_GL_MIXER_GET_PRIVATE(obj) \
53 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_GL_MIXER, GstGLMixerPrivate))
55 struct _GstGLMixerPrivate
59 gboolean gl_resource_ready;
60 GMutex gl_resource_lock;
61 GCond gl_resource_cond;
64 G_DEFINE_TYPE (GstGLMixerPad, gst_gl_mixer_pad, GST_TYPE_GL_BASE_MIXER_PAD);
67 gst_gl_mixer_pad_class_init (GstGLMixerPadClass * klass)
69 GObjectClass *gobject_class = (GObjectClass *) klass;
70 GstVideoAggregatorPadClass *vaggpad_class =
71 (GstVideoAggregatorPadClass *) klass;
73 gobject_class->set_property = gst_gl_mixer_pad_set_property;
74 gobject_class->get_property = gst_gl_mixer_pad_get_property;
76 gobject_class->finalize = gst_gl_mixer_pad_finalize;
78 vaggpad_class->set_info = NULL;
79 vaggpad_class->prepare_frame = NULL;
80 vaggpad_class->clean_frame = NULL;
84 gst_gl_mixer_pad_finalize (GObject * object)
86 G_OBJECT_CLASS (gst_gl_mixer_pad_parent_class)->finalize (object);
90 gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
91 GValue * value, GParamSpec * pspec)
95 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
101 gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
102 const GValue * value, GParamSpec * pspec)
106 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
112 _negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps)
114 GstGLMixer *mix = GST_GL_MIXER (vagg);
115 GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
116 GstGLBaseMixerClass *base_mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
119 mix->priv->negotiated = TRUE;
120 base_mix_class->supported_gl_api = mix_class->supported_gl_api;
122 gst_caps_replace (&mix->out_caps, caps);
124 ret = GST_VIDEO_AGGREGATOR_CLASS (parent_class)->negotiated_caps (vagg, caps);
126 mix->context = GST_GL_BASE_MIXER (mix)->context;
132 gst_gl_mixer_propose_allocation (GstGLBaseMixer * base_mix,
133 GstGLBaseMixerPad * base_pad, GstQuery * decide_query, GstQuery * query)
135 GstGLMixer *mix = GST_GL_MIXER (base_mix);
136 GstGLContext *context = base_mix->context;
137 GstBufferPool *pool = NULL;
138 GstStructure *config;
143 gst_query_parse_allocation (query, &caps, &need_pool);
151 if (!gst_video_info_from_caps (&info, caps))
154 GST_DEBUG_OBJECT (mix, "create new pool");
155 pool = gst_gl_buffer_pool_new (context);
157 /* the normal size of a frame */
160 config = gst_buffer_pool_get_config (pool);
161 gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
162 if (!gst_buffer_pool_set_config (pool, config))
167 gst_query_add_allocation_pool (query, pool, size, 1, 0);
168 gst_object_unref (pool);
171 /* we also support various metadata */
172 if (context->gl_vtable->FenceSync)
173 gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
180 GST_DEBUG_OBJECT (mix, "no caps specified");
185 GST_DEBUG_OBJECT (mix, "invalid caps specified");
190 GST_DEBUG_OBJECT (mix, "failed setting config");
196 gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix,
200 GstCaps *template_caps;
202 GST_DEBUG_OBJECT (pad, "try accept caps of %" GST_PTR_FORMAT, caps);
204 template_caps = gst_pad_get_pad_template_caps (pad);
205 template_caps = gst_caps_make_writable (template_caps);
207 ret = gst_caps_can_intersect (caps, template_caps);
208 GST_DEBUG_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT,
209 (ret ? "" : "not "), caps);
210 gst_caps_unref (template_caps);
215 /* copies the given caps */
217 _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
219 return gst_gl_caps_replace_all_caps_features (caps,
220 GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
224 gst_gl_mixer_pad_sink_getcaps (GstPad * pad, GstGLMixer * mix, GstCaps * filter)
227 GstCaps *template_caps;
228 GstCaps *filtered_caps;
229 GstCaps *returned_caps;
230 gboolean had_current_caps = TRUE;
232 template_caps = gst_pad_get_pad_template_caps (pad);
234 sinkcaps = gst_pad_get_current_caps (pad);
235 if (sinkcaps == NULL) {
236 had_current_caps = FALSE;
237 sinkcaps = template_caps;
239 sinkcaps = gst_caps_merge (sinkcaps, template_caps);
242 filtered_caps = sinkcaps;
244 filtered_caps = gst_caps_intersect (sinkcaps, filter);
245 returned_caps = gst_caps_intersect (filtered_caps, template_caps);
248 gst_caps_unref (filtered_caps);
249 if (had_current_caps)
250 gst_caps_unref (template_caps);
252 GST_DEBUG_OBJECT (pad, "returning %" GST_PTR_FORMAT, returned_caps);
254 return returned_caps;
258 gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
261 gboolean ret = FALSE;
262 GstGLMixer *mix = GST_GL_MIXER (agg);
264 GST_TRACE ("QUERY %" GST_PTR_FORMAT, query);
266 switch (GST_QUERY_TYPE (query)) {
269 GstCaps *filter, *caps;
271 gst_query_parse_caps (query, &filter);
272 caps = gst_gl_mixer_pad_sink_getcaps (GST_PAD (bpad), mix, filter);
273 gst_query_set_caps_result (query, caps);
274 gst_caps_unref (caps);
278 case GST_QUERY_ACCEPT_CAPS:
282 gst_query_parse_accept_caps (query, &caps);
283 ret = gst_gl_mixer_pad_sink_acceptcaps (GST_PAD (bpad), mix, caps);
284 gst_query_set_accept_caps_result (query, ret);
289 ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);
297 gst_gl_mixer_pad_init (GstGLMixerPad * mixerpad)
301 /* GLMixer signals and args */
313 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
316 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
317 (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
321 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
324 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
325 (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
329 static gboolean gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query);
330 static GstFlowReturn gst_gl_mixer_get_output_buffer (GstVideoAggregator *
331 videoaggregator, GstBuffer ** outbuf);
332 static gboolean gst_gl_mixer_stop (GstAggregator * agg);
333 static gboolean gst_gl_mixer_start (GstAggregator * agg);
336 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg,
337 GstBuffer * outbuffer);
339 static void gst_gl_mixer_set_property (GObject * object, guint prop_id,
340 const GValue * value, GParamSpec * pspec);
341 static void gst_gl_mixer_get_property (GObject * object, guint prop_id,
342 GValue * value, GParamSpec * pspec);
344 static gboolean gst_gl_mixer_decide_allocation (GstGLBaseMixer * mix,
347 static void gst_gl_mixer_finalize (GObject * object);
350 gst_gl_mixer_class_init (GstGLMixerClass * klass)
352 GObjectClass *gobject_class = (GObjectClass *) klass;
353 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
354 GstVideoAggregatorClass *videoaggregator_class =
355 (GstVideoAggregatorClass *) klass;
356 GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
357 GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_CLASS (klass);;
359 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "OpenGL mixer");
361 g_type_class_add_private (klass, sizeof (GstGLMixerPrivate));
363 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gl_mixer_finalize);
365 gobject_class->get_property = gst_gl_mixer_get_property;
366 gobject_class->set_property = gst_gl_mixer_set_property;
368 gst_element_class_add_pad_template (element_class,
369 gst_static_pad_template_get (&src_factory));
370 gst_element_class_add_pad_template (element_class,
371 gst_static_pad_template_get (&sink_factory));
373 agg_class->sinkpads_type = GST_TYPE_GL_MIXER_PAD;
374 agg_class->sink_query = gst_gl_mixer_sink_query;
375 agg_class->src_query = gst_gl_mixer_src_query;
376 agg_class->stop = gst_gl_mixer_stop;
377 agg_class->start = gst_gl_mixer_start;
379 videoaggregator_class->aggregate_frames = gst_gl_mixer_aggregate_frames;
380 videoaggregator_class->get_output_buffer = gst_gl_mixer_get_output_buffer;
381 videoaggregator_class->negotiated_caps = _negotiated_caps;
382 videoaggregator_class->update_caps = _update_caps;
383 videoaggregator_class->find_best_format = NULL;
385 mix_class->propose_allocation = gst_gl_mixer_propose_allocation;
386 mix_class->decide_allocation = gst_gl_mixer_decide_allocation;
388 /* Register the pad class */
389 g_type_class_ref (GST_TYPE_GL_MIXER_PAD);
391 klass->set_caps = NULL;
392 klass->supported_gl_api = GST_GL_API_ANY;
396 gst_gl_mixer_reset (GstGLMixer * mix)
398 mix->priv->negotiated = FALSE;
402 gst_gl_mixer_init (GstGLMixer * mix)
404 mix->priv = GST_GL_MIXER_GET_PRIVATE (mix);
405 mix->array_buffers = 0;
407 mix->depthbuffer = 0;
409 mix->priv->gl_resource_ready = FALSE;
410 g_mutex_init (&mix->priv->gl_resource_lock);
411 g_cond_init (&mix->priv->gl_resource_cond);
412 /* initialize variables */
413 gst_gl_mixer_reset (mix);
417 gst_gl_mixer_finalize (GObject * object)
419 GstGLMixer *mix = GST_GL_MIXER (object);
420 GstGLMixerPrivate *priv = mix->priv;
422 g_mutex_clear (&priv->gl_resource_lock);
423 g_cond_clear (&priv->gl_resource_cond);
424 G_OBJECT_CLASS (parent_class)->finalize (object);
428 gst_gl_mixer_query_caps (GstPad * pad, GstAggregator * agg, GstQuery * query)
430 GstCaps *filter, *current_caps, *retcaps, *template_caps;
432 gst_query_parse_caps (query, &filter);
434 template_caps = gst_pad_get_pad_template_caps (agg->srcpad);
436 current_caps = gst_pad_get_current_caps (pad);
437 if (current_caps == NULL)
438 retcaps = gst_caps_ref (template_caps);
440 retcaps = gst_caps_merge (current_caps, template_caps);
441 template_caps = NULL;
446 gst_caps_intersect_full (filter, retcaps, GST_CAPS_INTERSECT_FIRST);
447 gst_caps_unref (retcaps);
448 retcaps = current_caps;
451 gst_query_set_caps_result (query, retcaps);
452 gst_caps_unref (retcaps);
455 gst_caps_unref (template_caps);
461 gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query)
463 gboolean res = FALSE;
465 switch (GST_QUERY_TYPE (query)) {
467 res = gst_gl_mixer_query_caps (agg->srcpad, agg, query);
470 res = GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
478 gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator,
481 GstGLMixer *mix = GST_GL_MIXER (videoaggregator);
486 gst_gl_base_mixer_get_buffer_pool (GST_GL_BASE_MIXER (videoaggregator));
489 return GST_FLOW_NOT_NEGOTIATED;
491 if (!gst_buffer_pool_is_active (pool)) {
492 if (!gst_buffer_pool_set_active (pool, TRUE)) {
493 GST_ELEMENT_ERROR (mix, RESOURCE, SETTINGS,
494 ("failed to activate bufferpool"), ("failed to activate bufferpool"));
495 return GST_FLOW_ERROR;
499 ret = gst_buffer_pool_acquire_buffer (pool, outbuf, NULL);
500 gst_object_unref (pool);
506 gst_gl_mixer_decide_allocation (GstGLBaseMixer * base_mix, GstQuery * query)
508 GstGLMixer *mix = GST_GL_MIXER (base_mix);
509 GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
510 GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
511 GstGLContext *context = base_mix->context;
512 GstBufferPool *pool = NULL;
513 GstStructure *config;
515 guint min, max, size;
516 gboolean update_pool;
517 GError *error = NULL;
518 guint out_width, out_height;
520 out_width = GST_VIDEO_INFO_WIDTH (&vagg->info);
521 out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info);
523 g_mutex_lock (&mix->priv->gl_resource_lock);
524 mix->priv->gl_resource_ready = FALSE;
526 gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer);
528 mix->depthbuffer = 0;
531 if (!gst_gl_context_gen_fbo (context, out_width, out_height,
532 &mix->fbo, &mix->depthbuffer)) {
533 g_cond_signal (&mix->priv->gl_resource_cond);
534 g_mutex_unlock (&mix->priv->gl_resource_lock);
538 gst_query_parse_allocation (query, &caps, NULL);
540 mix->context = context;
541 if (mixer_class->set_caps)
542 mixer_class->set_caps (mix, caps);
544 mix->priv->gl_resource_ready = TRUE;
545 g_cond_signal (&mix->priv->gl_resource_cond);
546 g_mutex_unlock (&mix->priv->gl_resource_lock);
548 if (gst_query_get_n_allocation_pools (query) > 0) {
549 gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
555 gst_video_info_init (&vinfo);
556 gst_video_info_from_caps (&vinfo, caps);
563 pool = gst_gl_buffer_pool_new (context);
564 config = gst_buffer_pool_get_config (pool);
566 gst_buffer_pool_config_set_params (config, caps, size, min, max);
567 gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
569 gst_buffer_pool_set_config (pool, config);
572 gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
574 gst_query_add_allocation_pool (query, pool, size, min, max);
576 gst_object_unref (pool);
582 GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
589 gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
595 guint array_index = 0;
596 GstVideoFrame out_frame;
597 GstElement *element = GST_ELEMENT (mix);
598 GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
599 GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
600 GstGLMixerPrivate *priv = mix->priv;
602 GST_TRACE ("Processing buffers");
604 if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf,
605 GST_MAP_WRITE | GST_MAP_GL)) {
609 out_tex = *(guint *) out_frame.data[0];
611 GST_OBJECT_LOCK (mix);
612 walk = element->sinkpads;
614 i = mix->frames->len;
615 g_ptr_array_set_size (mix->frames, element->numsinkpads);
616 for (; i < element->numsinkpads; i++)
617 mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
619 GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data);
620 GstVideoAggregatorPad *vaggpad = walk->data;
621 GstGLMixerFrameData *frame;
623 frame = g_ptr_array_index (mix->frames, array_index);
627 walk = g_list_next (walk);
629 if (vaggpad->buffer != NULL) {
630 GstVideoInfo gl_info;
631 GstVideoFrame gl_frame;
632 GstGLSyncMeta *sync_meta;
634 gst_video_info_set_format (&gl_info,
635 GST_VIDEO_FORMAT_RGBA,
636 GST_VIDEO_INFO_WIDTH (&vaggpad->info),
637 GST_VIDEO_INFO_HEIGHT (&vaggpad->info));
639 sync_meta = gst_buffer_get_gl_sync_meta (vaggpad->buffer);
641 gst_gl_sync_meta_wait (sync_meta);
643 if (gst_video_frame_map (&gl_frame, &gl_info, vaggpad->buffer,
644 GST_MAP_READ | GST_MAP_GL)) {
645 frame->texture = *(guint *) gl_frame.data[0];
646 gst_video_frame_unmap (&gl_frame);
653 g_mutex_lock (&priv->gl_resource_lock);
654 if (!priv->gl_resource_ready)
655 g_cond_wait (&priv->gl_resource_cond, &priv->gl_resource_lock);
657 if (!priv->gl_resource_ready) {
658 g_mutex_unlock (&priv->gl_resource_lock);
659 GST_ERROR_OBJECT (mix,
660 "fbo used to render can't be created, do not run process_textures");
665 mix_class->process_textures (mix, mix->frames, out_tex);
667 g_mutex_unlock (&priv->gl_resource_lock);
670 GST_OBJECT_UNLOCK (mix);
672 gst_video_frame_unmap (&out_frame);
678 gst_gl_mixer_process_buffers (GstGLMixer * mix, GstBuffer * outbuf)
681 guint i, array_index = 0;
682 GstElement *element = GST_ELEMENT (mix);
683 GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
685 GST_OBJECT_LOCK (mix);
686 walk = GST_ELEMENT (mix)->sinkpads;
687 i = mix->frames->len;
688 g_ptr_array_set_size (mix->frames, element->numsinkpads);
689 for (; i < element->numsinkpads; i++)
690 mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
691 while (walk) { /* We walk with this list because it's ordered */
692 GstVideoAggregatorPad *vaggpad = walk->data;
694 walk = g_list_next (walk);
696 if (vaggpad->buffer != NULL) {
697 /* put buffer into array */
698 mix->array_buffers->pdata[array_index] = vaggpad->buffer;
702 GST_OBJECT_UNLOCK (mix);
704 return mix_class->process_buffers (mix, mix->array_buffers, outbuf);
708 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
710 gboolean res = FALSE;
711 GstGLMixer *mix = GST_GL_MIXER (vagg);
712 GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (vagg);
713 GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
714 GstGLSyncMeta *sync_meta;
716 if (mix_class->process_buffers)
717 res = gst_gl_mixer_process_buffers (mix, outbuf);
718 else if (mix_class->process_textures)
719 res = gst_gl_mixer_process_textures (mix, outbuf);
721 sync_meta = gst_buffer_get_gl_sync_meta (outbuf);
723 gst_gl_sync_meta_set_sync_point (sync_meta, context);
725 return res ? GST_FLOW_OK : GST_FLOW_ERROR;
729 gst_gl_mixer_get_property (GObject * object,
730 guint prop_id, GValue * value, GParamSpec * pspec)
734 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
740 gst_gl_mixer_set_property (GObject * object,
741 guint prop_id, const GValue * value, GParamSpec * pspec)
745 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
751 _free_glmixer_frame_data (GstGLMixerFrameData * frame)
753 g_slice_free1 (sizeof (GstGLMixerFrameData), frame);
757 gst_gl_mixer_start (GstAggregator * agg)
760 GstGLMixer *mix = GST_GL_MIXER (agg);
761 GstElement *element = GST_ELEMENT (agg);
763 GST_OBJECT_LOCK (mix);
764 mix->array_buffers = g_ptr_array_new_full (element->numsinkpads,
765 (GDestroyNotify) _free_glmixer_frame_data);
766 mix->frames = g_ptr_array_new_full (element->numsinkpads, NULL);
768 g_ptr_array_set_size (mix->array_buffers, element->numsinkpads);
769 g_ptr_array_set_size (mix->frames, element->numsinkpads);
771 for (i = 0; i < element->numsinkpads; i++)
772 mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
774 GST_OBJECT_UNLOCK (mix);
776 return GST_AGGREGATOR_CLASS (parent_class)->start (agg);
780 gst_gl_mixer_stop (GstAggregator * agg)
782 GstGLMixer *mix = GST_GL_MIXER (agg);
783 GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
784 GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
786 GST_OBJECT_LOCK (agg);
787 g_ptr_array_free (mix->frames, TRUE);
789 g_ptr_array_free (mix->array_buffers, TRUE);
790 mix->array_buffers = NULL;
791 GST_OBJECT_UNLOCK (agg);
793 if (mixer_class->reset)
794 mixer_class->reset (mix);
796 gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer);
798 mix->depthbuffer = 0;
801 gst_gl_mixer_reset (mix);
803 return GST_AGGREGATOR_CLASS (parent_class)->stop (agg);