gl: get the context from basemixer/basefilter
[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   gboolean ret;
116
117   mix->priv->negotiated = TRUE;
118
119   gst_caps_replace (&mix->out_caps, caps);
120
121   ret = GST_VIDEO_AGGREGATOR_CLASS (parent_class)->negotiated_caps (vagg, caps);
122
123   return ret;
124 }
125
126 static gboolean
127 gst_gl_mixer_propose_allocation (GstGLBaseMixer * base_mix,
128     GstGLBaseMixerPad * base_pad, GstQuery * decide_query, GstQuery * query)
129 {
130   GstGLMixer *mix = GST_GL_MIXER (base_mix);
131   GstGLContext *context = base_mix->context;
132   GstBufferPool *pool = NULL;
133   GstStructure *config;
134   GstCaps *caps;
135   guint size = 0;
136   gboolean need_pool;
137
138   gst_query_parse_allocation (query, &caps, &need_pool);
139
140   if (caps == NULL)
141     goto no_caps;
142
143   if (need_pool) {
144     GstVideoInfo info;
145
146     if (!gst_video_info_from_caps (&info, caps))
147       goto invalid_caps;
148
149     GST_DEBUG_OBJECT (mix, "create new pool");
150     pool = gst_gl_buffer_pool_new (context);
151
152     /* the normal size of a frame */
153     size = info.size;
154
155     config = gst_buffer_pool_get_config (pool);
156     gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
157     if (!gst_buffer_pool_set_config (pool, config))
158       goto config_failed;
159   }
160
161   if (pool) {
162     gst_query_add_allocation_pool (query, pool, size, 1, 0);
163     gst_object_unref (pool);
164   }
165
166   /* we also support various metadata */
167   if (context->gl_vtable->FenceSync)
168     gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
169
170   return TRUE;
171
172   /* ERRORS */
173 no_caps:
174   {
175     GST_DEBUG_OBJECT (mix, "no caps specified");
176     return FALSE;
177   }
178 invalid_caps:
179   {
180     GST_DEBUG_OBJECT (mix, "invalid caps specified");
181     return FALSE;
182   }
183 config_failed:
184   {
185     GST_DEBUG_OBJECT (mix, "failed setting config");
186     return FALSE;
187   }
188 }
189
190 static gboolean
191 gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix,
192     GstCaps * caps)
193 {
194   gboolean ret;
195   GstCaps *template_caps;
196
197   GST_DEBUG_OBJECT (pad, "try accept caps of %" GST_PTR_FORMAT, caps);
198
199   template_caps = gst_pad_get_pad_template_caps (pad);
200   template_caps = gst_caps_make_writable (template_caps);
201
202   ret = gst_caps_can_intersect (caps, template_caps);
203   GST_DEBUG_OBJECT (pad, "%saccepted caps %" GST_PTR_FORMAT,
204       (ret ? "" : "not "), caps);
205   gst_caps_unref (template_caps);
206
207   return ret;
208 }
209
210 /* copies the given caps */
211 static GstCaps *
212 _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
213 {
214   return gst_gl_caps_replace_all_caps_features (caps,
215       GST_CAPS_FEATURE_MEMORY_GL_MEMORY);
216 }
217
218 static GstCaps *
219 gst_gl_mixer_pad_sink_getcaps (GstPad * pad, GstGLMixer * mix, GstCaps * filter)
220 {
221   GstCaps *sinkcaps;
222   GstCaps *template_caps;
223   GstCaps *filtered_caps;
224   GstCaps *returned_caps;
225   gboolean had_current_caps = TRUE;
226
227   template_caps = gst_pad_get_pad_template_caps (pad);
228
229   sinkcaps = gst_pad_get_current_caps (pad);
230   if (sinkcaps == NULL) {
231     had_current_caps = FALSE;
232     sinkcaps = template_caps;
233   } else {
234     sinkcaps = gst_caps_merge (sinkcaps, template_caps);
235   }
236
237   filtered_caps = sinkcaps;
238   if (filter)
239     filtered_caps = gst_caps_intersect (sinkcaps, filter);
240   returned_caps = gst_caps_intersect (filtered_caps, template_caps);
241
242   if (filter)
243     gst_caps_unref (filtered_caps);
244   if (had_current_caps)
245     gst_caps_unref (template_caps);
246
247   GST_DEBUG_OBJECT (pad, "returning %" GST_PTR_FORMAT, returned_caps);
248
249   return returned_caps;
250 }
251
252 static gboolean
253 gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
254     GstQuery * query)
255 {
256   gboolean ret = FALSE;
257   GstGLMixer *mix = GST_GL_MIXER (agg);
258
259   GST_TRACE ("QUERY %" GST_PTR_FORMAT, query);
260
261   switch (GST_QUERY_TYPE (query)) {
262     case GST_QUERY_CAPS:
263     {
264       GstCaps *filter, *caps;
265
266       gst_query_parse_caps (query, &filter);
267       caps = gst_gl_mixer_pad_sink_getcaps (GST_PAD (bpad), mix, filter);
268       gst_query_set_caps_result (query, caps);
269       gst_caps_unref (caps);
270       ret = TRUE;
271       break;
272     }
273     case GST_QUERY_ACCEPT_CAPS:
274     {
275       GstCaps *caps;
276
277       gst_query_parse_accept_caps (query, &caps);
278       ret = gst_gl_mixer_pad_sink_acceptcaps (GST_PAD (bpad), mix, caps);
279       gst_query_set_accept_caps_result (query, ret);
280       ret = TRUE;
281       break;
282     }
283     default:
284       ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);
285       break;
286   }
287
288   return ret;
289 }
290
291 static void
292 gst_gl_mixer_pad_init (GstGLMixerPad * mixerpad)
293 {
294 }
295
296 /* GLMixer signals and args */
297 enum
298 {
299   /* FILL ME */
300   LAST_SIGNAL
301 };
302
303 enum
304 {
305   PROP_0,
306 };
307
308 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
309     GST_PAD_SRC,
310     GST_PAD_ALWAYS,
311     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
312         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
313             "RGBA"))
314     );
315
316 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
317     GST_PAD_SINK,
318     GST_PAD_REQUEST,
319     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
320         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
321             "RGBA"))
322     );
323
324 static gboolean gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query);
325 static GstFlowReturn gst_gl_mixer_get_output_buffer (GstVideoAggregator *
326     videoaggregator, GstBuffer ** outbuf);
327 static gboolean gst_gl_mixer_stop (GstAggregator * agg);
328 static gboolean gst_gl_mixer_start (GstAggregator * agg);
329
330 static GstFlowReturn
331 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg,
332     GstBuffer * outbuffer);
333
334 static void gst_gl_mixer_set_property (GObject * object, guint prop_id,
335     const GValue * value, GParamSpec * pspec);
336 static void gst_gl_mixer_get_property (GObject * object, guint prop_id,
337     GValue * value, GParamSpec * pspec);
338
339 static gboolean gst_gl_mixer_decide_allocation (GstGLBaseMixer * mix,
340     GstQuery * query);
341
342 static void gst_gl_mixer_finalize (GObject * object);
343
344 static void
345 gst_gl_mixer_class_init (GstGLMixerClass * klass)
346 {
347   GObjectClass *gobject_class = (GObjectClass *) klass;
348   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
349   GstVideoAggregatorClass *videoaggregator_class =
350       (GstVideoAggregatorClass *) klass;
351   GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
352   GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_CLASS (klass);;
353
354   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "OpenGL mixer");
355
356   g_type_class_add_private (klass, sizeof (GstGLMixerPrivate));
357
358   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gl_mixer_finalize);
359
360   gobject_class->get_property = gst_gl_mixer_get_property;
361   gobject_class->set_property = gst_gl_mixer_set_property;
362
363   gst_element_class_add_pad_template (element_class,
364       gst_static_pad_template_get (&src_factory));
365   gst_element_class_add_pad_template (element_class,
366       gst_static_pad_template_get (&sink_factory));
367
368   agg_class->sinkpads_type = GST_TYPE_GL_MIXER_PAD;
369   agg_class->sink_query = gst_gl_mixer_sink_query;
370   agg_class->src_query = gst_gl_mixer_src_query;
371   agg_class->stop = gst_gl_mixer_stop;
372   agg_class->start = gst_gl_mixer_start;
373
374   videoaggregator_class->aggregate_frames = gst_gl_mixer_aggregate_frames;
375   videoaggregator_class->get_output_buffer = gst_gl_mixer_get_output_buffer;
376   videoaggregator_class->negotiated_caps = _negotiated_caps;
377   videoaggregator_class->update_caps = _update_caps;
378   videoaggregator_class->find_best_format = NULL;
379
380   mix_class->propose_allocation = gst_gl_mixer_propose_allocation;
381   mix_class->decide_allocation = gst_gl_mixer_decide_allocation;
382
383   /* Register the pad class */
384   g_type_class_ref (GST_TYPE_GL_MIXER_PAD);
385
386   klass->set_caps = NULL;
387 }
388
389 static void
390 gst_gl_mixer_reset (GstGLMixer * mix)
391 {
392   mix->priv->negotiated = FALSE;
393 }
394
395 static void
396 gst_gl_mixer_init (GstGLMixer * mix)
397 {
398   mix->priv = GST_GL_MIXER_GET_PRIVATE (mix);
399   mix->array_buffers = 0;
400   mix->fbo = 0;
401   mix->depthbuffer = 0;
402
403   mix->priv->gl_resource_ready = FALSE;
404   g_mutex_init (&mix->priv->gl_resource_lock);
405   g_cond_init (&mix->priv->gl_resource_cond);
406   /* initialize variables */
407   gst_gl_mixer_reset (mix);
408 }
409
410 static void
411 gst_gl_mixer_finalize (GObject * object)
412 {
413   GstGLMixer *mix = GST_GL_MIXER (object);
414   GstGLMixerPrivate *priv = mix->priv;
415
416   g_mutex_clear (&priv->gl_resource_lock);
417   g_cond_clear (&priv->gl_resource_cond);
418   G_OBJECT_CLASS (parent_class)->finalize (object);
419 }
420
421 static gboolean
422 gst_gl_mixer_query_caps (GstPad * pad, GstAggregator * agg, GstQuery * query)
423 {
424   GstCaps *filter, *current_caps, *retcaps, *template_caps;
425
426   gst_query_parse_caps (query, &filter);
427
428   template_caps = gst_pad_get_pad_template_caps (agg->srcpad);
429
430   current_caps = gst_pad_get_current_caps (pad);
431   if (current_caps == NULL)
432     retcaps = gst_caps_ref (template_caps);
433   else {
434     retcaps = gst_caps_merge (current_caps, template_caps);
435     template_caps = NULL;
436   }
437
438   if (filter) {
439     current_caps =
440         gst_caps_intersect_full (filter, retcaps, GST_CAPS_INTERSECT_FIRST);
441     gst_caps_unref (retcaps);
442     retcaps = current_caps;
443   }
444
445   gst_query_set_caps_result (query, retcaps);
446   gst_caps_unref (retcaps);
447
448   if (template_caps)
449     gst_caps_unref (template_caps);
450
451   return TRUE;
452 }
453
454 static gboolean
455 gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query)
456 {
457   gboolean res = FALSE;
458
459   switch (GST_QUERY_TYPE (query)) {
460     case GST_QUERY_CAPS:
461       res = gst_gl_mixer_query_caps (agg->srcpad, agg, query);
462       break;
463     default:
464       res = GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
465       break;
466   }
467
468   return res;
469 }
470
471 static GstFlowReturn
472 gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator,
473     GstBuffer ** outbuf)
474 {
475   GstGLMixer *mix = GST_GL_MIXER (videoaggregator);
476   GstBufferPool *pool;
477   GstFlowReturn ret;
478
479   pool =
480       gst_gl_base_mixer_get_buffer_pool (GST_GL_BASE_MIXER (videoaggregator));
481
482   if (!pool)
483     return GST_FLOW_NOT_NEGOTIATED;
484
485   if (!gst_buffer_pool_is_active (pool)) {
486     if (!gst_buffer_pool_set_active (pool, TRUE)) {
487       GST_ELEMENT_ERROR (mix, RESOURCE, SETTINGS,
488           ("failed to activate bufferpool"), ("failed to activate bufferpool"));
489       return GST_FLOW_ERROR;
490     }
491   }
492
493   ret = gst_buffer_pool_acquire_buffer (pool, outbuf, NULL);
494   gst_object_unref (pool);
495
496   return ret;
497 }
498
499 static gboolean
500 gst_gl_mixer_decide_allocation (GstGLBaseMixer * base_mix, GstQuery * query)
501 {
502   GstGLMixer *mix = GST_GL_MIXER (base_mix);
503   GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
504   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
505   GstGLContext *context = base_mix->context;
506   GstBufferPool *pool = NULL;
507   GstStructure *config;
508   GstCaps *caps;
509   guint min, max, size;
510   gboolean update_pool;
511   GError *error = NULL;
512   guint out_width, out_height;
513
514   out_width = GST_VIDEO_INFO_WIDTH (&vagg->info);
515   out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info);
516
517   g_mutex_lock (&mix->priv->gl_resource_lock);
518   mix->priv->gl_resource_ready = FALSE;
519   if (mix->fbo) {
520     gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer);
521     mix->fbo = 0;
522     mix->depthbuffer = 0;
523   }
524
525   if (!gst_gl_context_gen_fbo (context, out_width, out_height,
526           &mix->fbo, &mix->depthbuffer)) {
527     g_cond_signal (&mix->priv->gl_resource_cond);
528     g_mutex_unlock (&mix->priv->gl_resource_lock);
529     goto context_error;
530   }
531
532   gst_query_parse_allocation (query, &caps, NULL);
533
534   if (mixer_class->set_caps)
535     mixer_class->set_caps (mix, caps);
536
537   mix->priv->gl_resource_ready = TRUE;
538   g_cond_signal (&mix->priv->gl_resource_cond);
539   g_mutex_unlock (&mix->priv->gl_resource_lock);
540
541   if (gst_query_get_n_allocation_pools (query) > 0) {
542     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
543
544     update_pool = TRUE;
545   } else {
546     GstVideoInfo vinfo;
547
548     gst_video_info_init (&vinfo);
549     gst_video_info_from_caps (&vinfo, caps);
550     size = vinfo.size;
551     min = max = 0;
552     update_pool = FALSE;
553   }
554
555   if (!pool)
556     pool = gst_gl_buffer_pool_new (context);
557   config = gst_buffer_pool_get_config (pool);
558
559   gst_buffer_pool_config_set_params (config, caps, size, min, max);
560   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
561
562   gst_buffer_pool_set_config (pool, config);
563
564   if (update_pool)
565     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
566   else
567     gst_query_add_allocation_pool (query, pool, size, min, max);
568
569   gst_object_unref (pool);
570
571   return TRUE;
572
573 context_error:
574   {
575     GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
576         (NULL));
577     return FALSE;
578   }
579 }
580
581 gboolean
582 gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
583 {
584   guint i;
585   GList *walk;
586   guint out_tex;
587   gboolean res = TRUE;
588   guint array_index = 0;
589   GstVideoFrame out_frame;
590   GstElement *element = GST_ELEMENT (mix);
591   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
592   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
593   GstGLMixerPrivate *priv = mix->priv;
594
595   GST_TRACE ("Processing buffers");
596
597   if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf,
598           GST_MAP_WRITE | GST_MAP_GL)) {
599     return FALSE;
600   }
601
602   out_tex = *(guint *) out_frame.data[0];
603
604   GST_OBJECT_LOCK (mix);
605   walk = element->sinkpads;
606
607   i = mix->frames->len;
608   g_ptr_array_set_size (mix->frames, element->numsinkpads);
609   for (; i < element->numsinkpads; i++)
610     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
611   while (walk) {
612     GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data);
613     GstVideoAggregatorPad *vaggpad = walk->data;
614     GstGLMixerFrameData *frame;
615
616     frame = g_ptr_array_index (mix->frames, array_index);
617     frame->pad = pad;
618     frame->texture = 0;
619
620     walk = g_list_next (walk);
621
622     if (vaggpad->buffer != NULL) {
623       GstVideoInfo gl_info;
624       GstVideoFrame gl_frame;
625       GstGLSyncMeta *sync_meta;
626
627       gst_video_info_set_format (&gl_info,
628           GST_VIDEO_FORMAT_RGBA,
629           GST_VIDEO_INFO_WIDTH (&vaggpad->info),
630           GST_VIDEO_INFO_HEIGHT (&vaggpad->info));
631
632       sync_meta = gst_buffer_get_gl_sync_meta (vaggpad->buffer);
633       if (sync_meta)
634         gst_gl_sync_meta_wait (sync_meta);
635
636       if (gst_video_frame_map (&gl_frame, &gl_info, vaggpad->buffer,
637               GST_MAP_READ | GST_MAP_GL)) {
638         frame->texture = *(guint *) gl_frame.data[0];
639         gst_video_frame_unmap (&gl_frame);
640       }
641     }
642
643     ++array_index;
644   }
645
646   g_mutex_lock (&priv->gl_resource_lock);
647   if (!priv->gl_resource_ready)
648     g_cond_wait (&priv->gl_resource_cond, &priv->gl_resource_lock);
649
650   if (!priv->gl_resource_ready) {
651     g_mutex_unlock (&priv->gl_resource_lock);
652     GST_ERROR_OBJECT (mix,
653         "fbo used to render can't be created, do not run process_textures");
654     res = FALSE;
655     goto out;
656   }
657
658   mix_class->process_textures (mix, mix->frames, out_tex);
659
660   g_mutex_unlock (&priv->gl_resource_lock);
661
662 out:
663   GST_OBJECT_UNLOCK (mix);
664
665   gst_video_frame_unmap (&out_frame);
666
667   return res;
668 }
669
670 static gboolean
671 gst_gl_mixer_process_buffers (GstGLMixer * mix, GstBuffer * outbuf)
672 {
673   GList *walk;
674   guint i, array_index = 0;
675   GstElement *element = GST_ELEMENT (mix);
676   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
677
678   GST_OBJECT_LOCK (mix);
679   walk = GST_ELEMENT (mix)->sinkpads;
680   i = mix->frames->len;
681   g_ptr_array_set_size (mix->frames, element->numsinkpads);
682   for (; i < element->numsinkpads; i++)
683     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
684   while (walk) {                /* We walk with this list because it's ordered */
685     GstVideoAggregatorPad *vaggpad = walk->data;
686
687     walk = g_list_next (walk);
688
689     if (vaggpad->buffer != NULL) {
690       /* put buffer into array */
691       mix->array_buffers->pdata[array_index] = vaggpad->buffer;
692     }
693     ++array_index;
694   }
695   GST_OBJECT_UNLOCK (mix);
696
697   return mix_class->process_buffers (mix, mix->array_buffers, outbuf);
698 }
699
700 static GstFlowReturn
701 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
702 {
703   gboolean res = FALSE;
704   GstGLMixer *mix = GST_GL_MIXER (vagg);
705   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (vagg);
706   GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
707   GstGLSyncMeta *sync_meta;
708
709   if (mix_class->process_buffers)
710     res = gst_gl_mixer_process_buffers (mix, outbuf);
711   else if (mix_class->process_textures)
712     res = gst_gl_mixer_process_textures (mix, outbuf);
713
714   sync_meta = gst_buffer_get_gl_sync_meta (outbuf);
715   if (sync_meta)
716     gst_gl_sync_meta_set_sync_point (sync_meta, context);
717
718   return res ? GST_FLOW_OK : GST_FLOW_ERROR;
719 }
720
721 static void
722 gst_gl_mixer_get_property (GObject * object,
723     guint prop_id, GValue * value, GParamSpec * pspec)
724 {
725   switch (prop_id) {
726     default:
727       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
728       break;
729   }
730 }
731
732 static void
733 gst_gl_mixer_set_property (GObject * object,
734     guint prop_id, const GValue * value, GParamSpec * pspec)
735 {
736   switch (prop_id) {
737     default:
738       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
739       break;
740   }
741 }
742
743 static void
744 _free_glmixer_frame_data (GstGLMixerFrameData * frame)
745 {
746   g_slice_free1 (sizeof (GstGLMixerFrameData), frame);
747 }
748
749 static gboolean
750 gst_gl_mixer_start (GstAggregator * agg)
751 {
752   guint i;
753   GstGLMixer *mix = GST_GL_MIXER (agg);
754   GstElement *element = GST_ELEMENT (agg);
755
756   GST_OBJECT_LOCK (mix);
757   mix->array_buffers = g_ptr_array_new_full (element->numsinkpads,
758       (GDestroyNotify) _free_glmixer_frame_data);
759   mix->frames = g_ptr_array_new_full (element->numsinkpads, NULL);
760
761   g_ptr_array_set_size (mix->array_buffers, element->numsinkpads);
762   g_ptr_array_set_size (mix->frames, element->numsinkpads);
763
764   for (i = 0; i < element->numsinkpads; i++)
765     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
766
767   GST_OBJECT_UNLOCK (mix);
768
769   return GST_AGGREGATOR_CLASS (parent_class)->start (agg);
770 }
771
772 static gboolean
773 gst_gl_mixer_stop (GstAggregator * agg)
774 {
775   GstGLMixer *mix = GST_GL_MIXER (agg);
776   GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
777   GstGLContext *context = GST_GL_BASE_MIXER (mix)->context;
778
779   GST_OBJECT_LOCK (agg);
780   g_ptr_array_free (mix->frames, TRUE);
781   mix->frames = NULL;
782   g_ptr_array_free (mix->array_buffers, TRUE);
783   mix->array_buffers = NULL;
784   GST_OBJECT_UNLOCK (agg);
785
786   if (mixer_class->reset)
787     mixer_class->reset (mix);
788   if (mix->fbo) {
789     gst_gl_context_del_fbo (context, mix->fbo, mix->depthbuffer);
790     mix->fbo = 0;
791     mix->depthbuffer = 0;
792   }
793
794   gst_gl_mixer_reset (mix);
795
796   return GST_AGGREGATOR_CLASS (parent_class)->stop (agg);
797 }