glmixer: remove usage of upload/download objects
[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/video/video.h>
28
29 #include "gstglmixer.h"
30
31 #if GST_GL_HAVE_PLATFORM_EGL
32 #include <gst/gl/egl/gsteglimagememory.h>
33 #endif
34
35 #define gst_gl_mixer_parent_class parent_class
36 G_DEFINE_ABSTRACT_TYPE (GstGLMixer, gst_gl_mixer, GST_TYPE_GL_BASE_MIXER);
37
38 #define GST_CAT_DEFAULT gst_gl_mixer_debug
39 GST_DEBUG_CATEGORY (gst_gl_mixer_debug);
40
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);
46
47 enum
48 {
49   PROP_PAD_0
50 };
51
52 #define GST_GL_MIXER_GET_PRIVATE(obj)  \
53     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_GL_MIXER, GstGLMixerPrivate))
54
55 struct _GstGLMixerPrivate
56 {
57   gboolean negotiated;
58
59   gboolean gl_resource_ready;
60   GMutex gl_resource_lock;
61   GCond gl_resource_cond;
62 };
63
64 G_DEFINE_TYPE (GstGLMixerPad, gst_gl_mixer_pad, GST_TYPE_GL_BASE_MIXER_PAD);
65
66 static void
67 gst_gl_mixer_pad_class_init (GstGLMixerPadClass * klass)
68 {
69   GObjectClass *gobject_class = (GObjectClass *) klass;
70   GstVideoAggregatorPadClass *vaggpad_class =
71       (GstVideoAggregatorPadClass *) klass;
72
73   gobject_class->set_property = gst_gl_mixer_pad_set_property;
74   gobject_class->get_property = gst_gl_mixer_pad_get_property;
75
76   gobject_class->finalize = gst_gl_mixer_pad_finalize;
77
78   vaggpad_class->set_info = NULL;
79   vaggpad_class->prepare_frame = NULL;
80   vaggpad_class->clean_frame = NULL;
81 }
82
83 static void
84 gst_gl_mixer_pad_finalize (GObject * object)
85 {
86   G_OBJECT_CLASS (gst_gl_mixer_pad_parent_class)->finalize (object);
87 }
88
89 static void
90 gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
91     GValue * value, GParamSpec * pspec)
92 {
93   switch (prop_id) {
94     default:
95       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
96       break;
97   }
98 }
99
100 static void
101 gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
102     const GValue * value, GParamSpec * pspec)
103 {
104   switch (prop_id) {
105     default:
106       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
107       break;
108   }
109 }
110
111 static gboolean
112 _negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps)
113 {
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);
117   gboolean ret;
118
119   mix->priv->negotiated = TRUE;
120   base_mix_class->supported_gl_api = mix_class->supported_gl_api;
121
122   gst_caps_replace (&mix->out_caps, caps);
123
124   ret = GST_VIDEO_AGGREGATOR_CLASS (parent_class)->negotiated_caps (vagg, caps);
125
126   mix->context = GST_GL_BASE_MIXER (mix)->context;
127
128   return ret;
129 }
130
131 static gboolean
132 gst_gl_mixer_propose_allocation (GstGLBaseMixer * base_mix,
133     GstGLBaseMixerPad * base_pad, GstQuery * decide_query, GstQuery * query)
134 {
135   GstGLMixer *mix = GST_GL_MIXER (base_mix);
136   GstGLContext *context = base_mix->context;
137   GstBufferPool *pool = NULL;
138   GstStructure *config;
139   GstCaps *caps;
140   guint size = 0;
141   gboolean need_pool;
142
143   gst_query_parse_allocation (query, &caps, &need_pool);
144
145   if (caps == NULL)
146     goto no_caps;
147
148   if (need_pool) {
149     GstVideoInfo info;
150
151     if (!gst_video_info_from_caps (&info, caps))
152       goto invalid_caps;
153
154     GST_DEBUG_OBJECT (mix, "create new pool");
155     pool = gst_gl_buffer_pool_new (context);
156
157     /* the normal size of a frame */
158     size = info.size;
159
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))
163       goto config_failed;
164   }
165
166   if (pool) {
167     gst_query_add_allocation_pool (query, pool, size, 1, 0);
168     gst_object_unref (pool);
169   }
170
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);
174
175   return TRUE;
176
177   /* ERRORS */
178 no_caps:
179   {
180     GST_DEBUG_OBJECT (mix, "no caps specified");
181     return FALSE;
182   }
183 invalid_caps:
184   {
185     GST_DEBUG_OBJECT (mix, "invalid caps specified");
186     return FALSE;
187   }
188 config_failed:
189   {
190     GST_DEBUG_OBJECT (mix, "failed setting config");
191     return FALSE;
192   }
193 }
194
195 static gboolean
196 gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix,
197     GstCaps * caps)
198 {
199   gboolean ret;
200   GstCaps *template_caps;
201
202   GST_DEBUG_OBJECT (pad, "try accept caps of %" GST_PTR_FORMAT, caps);
203
204   template_caps = gst_pad_get_pad_template_caps (pad);
205   template_caps = gst_caps_make_writable (template_caps);
206
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);
211
212   return ret;
213 }
214
215 /* copies the given caps */
216 static GstCaps *
217 _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
218 {
219   return gst_gl_caps_replace_all_caps_features (caps,
220       GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
221 }
222
223 static GstCaps *
224 gst_gl_mixer_pad_sink_getcaps (GstPad * pad, GstGLMixer * mix, GstCaps * filter)
225 {
226   GstCaps *sinkcaps;
227   GstCaps *template_caps;
228   GstCaps *filtered_caps;
229   GstCaps *returned_caps;
230   gboolean had_current_caps = TRUE;
231
232   template_caps = gst_pad_get_pad_template_caps (pad);
233
234   sinkcaps = gst_pad_get_current_caps (pad);
235   if (sinkcaps == NULL) {
236     had_current_caps = FALSE;
237     sinkcaps = template_caps;
238   } else {
239     sinkcaps = gst_caps_merge (sinkcaps, template_caps);
240   }
241
242   filtered_caps = sinkcaps;
243   if (filter)
244     filtered_caps = gst_caps_intersect (sinkcaps, filter);
245   returned_caps = gst_caps_intersect (filtered_caps, template_caps);
246
247   if (filter)
248     gst_caps_unref (filtered_caps);
249   if (had_current_caps)
250     gst_caps_unref (template_caps);
251
252   GST_DEBUG_OBJECT (pad, "returning %" GST_PTR_FORMAT, returned_caps);
253
254   return returned_caps;
255 }
256
257 static gboolean
258 gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
259     GstQuery * query)
260 {
261   gboolean ret = FALSE;
262   GstGLMixer *mix = GST_GL_MIXER (agg);
263
264   GST_TRACE ("QUERY %" GST_PTR_FORMAT, query);
265
266   switch (GST_QUERY_TYPE (query)) {
267     case GST_QUERY_CAPS:
268     {
269       GstCaps *filter, *caps;
270
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);
275       ret = TRUE;
276       break;
277     }
278     case GST_QUERY_ACCEPT_CAPS:
279     {
280       GstCaps *caps;
281
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);
285       ret = TRUE;
286       break;
287     }
288     default:
289       ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);
290       break;
291   }
292
293   return ret;
294 }
295
296 static void
297 gst_gl_mixer_pad_init (GstGLMixerPad * mixerpad)
298 {
299 }
300
301 /* GLMixer signals and args */
302 enum
303 {
304   /* FILL ME */
305   LAST_SIGNAL
306 };
307
308 enum
309 {
310   PROP_0,
311 };
312
313 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
314     GST_PAD_SRC,
315     GST_PAD_ALWAYS,
316     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
317         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
318             "RGBA"))
319     );
320
321 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
322     GST_PAD_SINK,
323     GST_PAD_REQUEST,
324     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
325         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
326             "RGBA"))
327     );
328
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);
334
335 static GstFlowReturn
336 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg,
337     GstBuffer * outbuffer);
338
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);
343
344 static gboolean gst_gl_mixer_decide_allocation (GstGLBaseMixer * mix,
345     GstQuery * query);
346
347 static void gst_gl_mixer_finalize (GObject * object);
348
349 static void
350 gst_gl_mixer_class_init (GstGLMixerClass * klass)
351 {
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);;
358
359   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "OpenGL mixer");
360
361   g_type_class_add_private (klass, sizeof (GstGLMixerPrivate));
362
363   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gl_mixer_finalize);
364
365   gobject_class->get_property = gst_gl_mixer_get_property;
366   gobject_class->set_property = gst_gl_mixer_set_property;
367
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));
372
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;
378
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;
384
385   mix_class->propose_allocation = gst_gl_mixer_propose_allocation;
386   mix_class->decide_allocation = gst_gl_mixer_decide_allocation;
387
388   /* Register the pad class */
389   g_type_class_ref (GST_TYPE_GL_MIXER_PAD);
390
391   klass->set_caps = NULL;
392   klass->supported_gl_api = GST_GL_API_ANY;
393 }
394
395 static void
396 gst_gl_mixer_reset (GstGLMixer * mix)
397 {
398   mix->priv->negotiated = FALSE;
399 }
400
401 static void
402 gst_gl_mixer_init (GstGLMixer * mix)
403 {
404   mix->priv = GST_GL_MIXER_GET_PRIVATE (mix);
405   mix->array_buffers = 0;
406   mix->fbo = 0;
407   mix->depthbuffer = 0;
408
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);
414 }
415
416 static void
417 gst_gl_mixer_finalize (GObject * object)
418 {
419   GstGLMixer *mix = GST_GL_MIXER (object);
420   GstGLMixerPrivate *priv = mix->priv;
421
422   g_mutex_clear (&priv->gl_resource_lock);
423   g_cond_clear (&priv->gl_resource_cond);
424   G_OBJECT_CLASS (parent_class)->finalize (object);
425 }
426
427 static gboolean
428 gst_gl_mixer_query_caps (GstPad * pad, GstAggregator * agg, GstQuery * query)
429 {
430   GstCaps *filter, *current_caps, *retcaps, *template_caps;
431
432   gst_query_parse_caps (query, &filter);
433
434   template_caps = gst_pad_get_pad_template_caps (agg->srcpad);
435
436   current_caps = gst_pad_get_current_caps (pad);
437   if (current_caps == NULL)
438     retcaps = gst_caps_ref (template_caps);
439   else {
440     retcaps = gst_caps_merge (current_caps, template_caps);
441     template_caps = NULL;
442   }
443
444   if (filter) {
445     current_caps =
446         gst_caps_intersect_full (filter, retcaps, GST_CAPS_INTERSECT_FIRST);
447     gst_caps_unref (retcaps);
448     retcaps = current_caps;
449   }
450
451   gst_query_set_caps_result (query, retcaps);
452   gst_caps_unref (retcaps);
453
454   if (template_caps)
455     gst_caps_unref (template_caps);
456
457   return TRUE;
458 }
459
460 static gboolean
461 gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query)
462 {
463   gboolean res = FALSE;
464
465   switch (GST_QUERY_TYPE (query)) {
466     case GST_QUERY_CAPS:
467       res = gst_gl_mixer_query_caps (agg->srcpad, agg, query);
468       break;
469     default:
470       res = GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
471       break;
472   }
473
474   return res;
475 }
476
477 static GstFlowReturn
478 gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator,
479     GstBuffer ** outbuf)
480 {
481   GstGLMixer *mix = GST_GL_MIXER (videoaggregator);
482   GstBufferPool *pool;
483   GstFlowReturn ret;
484
485   pool =
486       gst_gl_base_mixer_get_buffer_pool (GST_GL_BASE_MIXER (videoaggregator));
487
488   if (!pool)
489     return GST_FLOW_NOT_NEGOTIATED;
490
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;
496     }
497   }
498
499   ret = gst_buffer_pool_acquire_buffer (pool, outbuf, NULL);
500   gst_object_unref (pool);
501
502   return ret;
503 }
504
505 static gboolean
506 gst_gl_mixer_decide_allocation (GstGLBaseMixer * base_mix, GstQuery * query)
507 {
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;
514   GstCaps *caps;
515   guint min, max, size;
516   gboolean update_pool;
517   GError *error = NULL;
518   guint out_width, out_height;
519
520   out_width = GST_VIDEO_INFO_WIDTH (&vagg->info);
521   out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info);
522
523   g_mutex_lock (&mix->priv->gl_resource_lock);
524   mix->priv->gl_resource_ready = FALSE;
525   if (mix->fbo) {
526     gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer);
527     mix->fbo = 0;
528     mix->depthbuffer = 0;
529   }
530
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);
535     goto context_error;
536   }
537
538   gst_query_parse_allocation (query, &caps, NULL);
539
540   mix->context = context;
541   if (mixer_class->set_caps)
542     mixer_class->set_caps (mix, caps);
543
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);
547
548   if (gst_query_get_n_allocation_pools (query) > 0) {
549     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
550
551     update_pool = TRUE;
552   } else {
553     GstVideoInfo vinfo;
554
555     gst_video_info_init (&vinfo);
556     gst_video_info_from_caps (&vinfo, caps);
557     size = vinfo.size;
558     min = max = 0;
559     update_pool = FALSE;
560   }
561
562   if (!pool)
563     pool = gst_gl_buffer_pool_new (context);
564   config = gst_buffer_pool_get_config (pool);
565
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);
568
569   gst_buffer_pool_set_config (pool, config);
570
571   if (update_pool)
572     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
573   else
574     gst_query_add_allocation_pool (query, pool, size, min, max);
575
576   gst_object_unref (pool);
577
578   return TRUE;
579
580 context_error:
581   {
582     GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
583         (NULL));
584     return FALSE;
585   }
586 }
587
588 gboolean
589 gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
590 {
591   guint i;
592   GList *walk;
593   guint out_tex;
594   gboolean res = TRUE;
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;
601
602   GST_TRACE ("Processing buffers");
603
604   if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf,
605           GST_MAP_WRITE | GST_MAP_GL)) {
606     return FALSE;
607   }
608
609   out_tex = *(guint *) out_frame.data[0];
610
611   GST_OBJECT_LOCK (mix);
612   walk = element->sinkpads;
613
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);
618   while (walk) {
619     GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data);
620     GstVideoAggregatorPad *vaggpad = walk->data;
621     GstGLMixerFrameData *frame;
622
623     frame = g_ptr_array_index (mix->frames, array_index);
624     frame->pad = pad;
625     frame->texture = 0;
626
627     walk = g_list_next (walk);
628
629     if (vaggpad->buffer != NULL) {
630       GstVideoInfo gl_info;
631       GstVideoFrame gl_frame;
632       GstGLSyncMeta *sync_meta;
633
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));
638
639       sync_meta = gst_buffer_get_gl_sync_meta (vaggpad->buffer);
640       if (sync_meta)
641         gst_gl_sync_meta_wait (sync_meta);
642
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);
647       }
648     }
649
650     ++array_index;
651   }
652
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);
656
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");
661     res = FALSE;
662     goto out;
663   }
664
665   mix_class->process_textures (mix, mix->frames, out_tex);
666
667   g_mutex_unlock (&priv->gl_resource_lock);
668
669 out:
670   GST_OBJECT_UNLOCK (mix);
671
672   gst_video_frame_unmap (&out_frame);
673
674   return res;
675 }
676
677 static gboolean
678 gst_gl_mixer_process_buffers (GstGLMixer * mix, GstBuffer * outbuf)
679 {
680   GList *walk;
681   guint i, array_index = 0;
682   GstElement *element = GST_ELEMENT (mix);
683   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
684
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;
693
694     walk = g_list_next (walk);
695
696     if (vaggpad->buffer != NULL) {
697       /* put buffer into array */
698       mix->array_buffers->pdata[array_index] = vaggpad->buffer;
699     }
700     ++array_index;
701   }
702   GST_OBJECT_UNLOCK (mix);
703
704   return mix_class->process_buffers (mix, mix->array_buffers, outbuf);
705 }
706
707 static GstFlowReturn
708 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
709 {
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;
715
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);
720
721   sync_meta = gst_buffer_get_gl_sync_meta (outbuf);
722   if (sync_meta)
723     gst_gl_sync_meta_set_sync_point (sync_meta, context);
724
725   return res ? GST_FLOW_OK : GST_FLOW_ERROR;
726 }
727
728 static void
729 gst_gl_mixer_get_property (GObject * object,
730     guint prop_id, GValue * value, GParamSpec * pspec)
731 {
732   switch (prop_id) {
733     default:
734       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
735       break;
736   }
737 }
738
739 static void
740 gst_gl_mixer_set_property (GObject * object,
741     guint prop_id, const GValue * value, GParamSpec * pspec)
742 {
743   switch (prop_id) {
744     default:
745       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
746       break;
747   }
748 }
749
750 static void
751 _free_glmixer_frame_data (GstGLMixerFrameData * frame)
752 {
753   g_slice_free1 (sizeof (GstGLMixerFrameData), frame);
754 }
755
756 static gboolean
757 gst_gl_mixer_start (GstAggregator * agg)
758 {
759   guint i;
760   GstGLMixer *mix = GST_GL_MIXER (agg);
761   GstElement *element = GST_ELEMENT (agg);
762
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);
767
768   g_ptr_array_set_size (mix->array_buffers, element->numsinkpads);
769   g_ptr_array_set_size (mix->frames, element->numsinkpads);
770
771   for (i = 0; i < element->numsinkpads; i++)
772     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
773
774   GST_OBJECT_UNLOCK (mix);
775
776   return GST_AGGREGATOR_CLASS (parent_class)->start (agg);
777 }
778
779 static gboolean
780 gst_gl_mixer_stop (GstAggregator * agg)
781 {
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;
785
786   GST_OBJECT_LOCK (agg);
787   g_ptr_array_free (mix->frames, TRUE);
788   mix->frames = NULL;
789   g_ptr_array_free (mix->array_buffers, TRUE);
790   mix->array_buffers = NULL;
791   GST_OBJECT_UNLOCK (agg);
792
793   if (mixer_class->reset)
794     mixer_class->reset (mix);
795   if (mix->fbo) {
796     gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer);
797     mix->fbo = 0;
798     mix->depthbuffer = 0;
799   }
800
801   gst_gl_mixer_reset (mix);
802
803   return GST_AGGREGATOR_CLASS (parent_class)->stop (agg);
804 }