gl: Removed unreachable break, unused variable
[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 #define gst_gl_mixer_parent_class parent_class
40 G_DEFINE_ABSTRACT_TYPE (GstGLMixer, gst_gl_mixer, GST_TYPE_VIDEO_AGGREGATOR);
41 static gboolean gst_gl_mixer_do_bufferpool (GstGLMixer * mix,
42     GstCaps * outcaps);
43
44
45 #define GST_CAT_DEFAULT gst_gl_mixer_debug
46 GST_DEBUG_CATEGORY (gst_gl_mixer_debug);
47
48 static void gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
49     GValue * value, GParamSpec * pspec);
50 static void gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
51     const GValue * value, GParamSpec * pspec);
52 static void gst_gl_mixer_pad_finalize (GObject * object);
53
54 static void gst_gl_mixer_set_context (GstElement * element,
55     GstContext * context);
56
57 enum
58 {
59   PROP_PAD_0
60 };
61
62 #define GST_GL_MIXER_GET_PRIVATE(obj)  \
63     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_GL_MIXER, GstGLMixerPrivate))
64
65 struct _GstGLMixerPrivate
66 {
67   gboolean negotiated;
68
69   GstBufferPool *pool;
70   gboolean pool_active;
71   GstAllocator *allocator;
72   GstAllocationParams params;
73   GstQuery *query;
74
75   gboolean gl_resource_ready;
76   GMutex gl_resource_lock;
77   GCond gl_resource_cond;
78 };
79
80 G_DEFINE_TYPE (GstGLMixerPad, gst_gl_mixer_pad, GST_TYPE_VIDEO_AGGREGATOR_PAD);
81
82 static void
83 gst_gl_mixer_pad_class_init (GstGLMixerPadClass * klass)
84 {
85   GObjectClass *gobject_class = (GObjectClass *) klass;
86
87   gobject_class->set_property = gst_gl_mixer_pad_set_property;
88   gobject_class->get_property = gst_gl_mixer_pad_get_property;
89
90   gobject_class->finalize = gst_gl_mixer_pad_finalize;
91 }
92
93 static void
94 gst_gl_mixer_pad_finalize (GObject * object)
95 {
96   GstGLMixerPad *pad = GST_GL_MIXER_PAD (object);
97
98   if (pad->upload) {
99     gst_object_unref (pad->upload);
100     pad->upload = NULL;
101   }
102 }
103
104 static void
105 gst_gl_mixer_pad_get_property (GObject * object, guint prop_id,
106     GValue * value, GParamSpec * pspec)
107 {
108   switch (prop_id) {
109     default:
110       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111       break;
112   }
113 }
114
115 static void
116 gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
117     const GValue * value, GParamSpec * pspec)
118 {
119   switch (prop_id) {
120     default:
121       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122       break;
123   }
124 }
125
126 static gboolean
127 _negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps)
128 {
129   GstGLMixer *mix = GST_GL_MIXER (vagg);
130   gboolean ret = gst_gl_mixer_do_bufferpool (mix, caps);
131
132   mix->priv->negotiated = ret;
133
134   return ret;
135 }
136
137 static gboolean
138 gst_gl_mixer_propose_allocation (GstGLMixer * mix,
139     GstQuery * decide_query, GstQuery * query)
140 {
141   GstBufferPool *pool;
142   GstStructure *config;
143   GstCaps *caps;
144   guint size = 0;
145   gboolean need_pool;
146   GError *error = NULL;
147   GstStructure *gl_context;
148   gchar *platform, *gl_apis;
149   gpointer handle;
150   GstAllocator *allocator = NULL;
151   GstAllocationParams params;
152
153   gst_query_parse_allocation (query, &caps, &need_pool);
154
155   if (caps == NULL)
156     goto no_caps;
157
158   if ((pool = mix->priv->pool))
159     gst_object_ref (pool);
160
161   if (pool != NULL) {
162     GstCaps *pcaps;
163
164     /* we had a pool, check caps */
165     GST_DEBUG_OBJECT (mix, "check existing pool caps");
166     config = gst_buffer_pool_get_config (pool);
167     gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
168
169     if (!gst_caps_is_equal (caps, pcaps)) {
170       GST_DEBUG_OBJECT (mix, "pool has different caps");
171       /* different caps, we can't use this pool */
172       gst_object_unref (pool);
173       pool = NULL;
174     }
175     gst_structure_free (config);
176   }
177
178   if (!gst_gl_ensure_display (mix, &mix->display))
179     return FALSE;
180
181   if (!mix->context) {
182     mix->context = gst_gl_context_new (mix->display);
183     if (!gst_gl_context_create (mix->context, NULL, &error))
184       goto context_error;
185   }
186
187   if (pool == NULL && need_pool) {
188     GstVideoInfo info;
189
190     if (!gst_video_info_from_caps (&info, caps))
191       goto invalid_caps;
192
193     GST_DEBUG_OBJECT (mix, "create new pool");
194     pool = gst_gl_buffer_pool_new (mix->context);
195
196     /* the normal size of a frame */
197     size = info.size;
198
199     config = gst_buffer_pool_get_config (pool);
200     gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
201     if (!gst_buffer_pool_set_config (pool, config))
202       goto config_failed;
203   }
204
205   if (pool) {
206     gst_query_add_allocation_pool (query, pool, size, 1, 0);
207     gst_object_unref (pool);
208   }
209
210   /* we also support various metadata */
211   gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
212
213   gl_apis = gst_gl_api_to_string (gst_gl_context_get_gl_api (mix->context));
214   platform =
215       gst_gl_platform_to_string (gst_gl_context_get_gl_platform (mix->context));
216   handle = (gpointer) gst_gl_context_get_gl_context (mix->context);
217
218   gl_context =
219       gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext",
220       GST_GL_TYPE_CONTEXT, mix->context, "gst.gl.context.handle",
221       G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform,
222       "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
223   gst_query_add_allocation_meta (query,
224       GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context);
225
226   g_free (gl_apis);
227   g_free (platform);
228   gst_structure_free (gl_context);
229
230   gst_allocation_params_init (&params);
231
232   allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR);
233   gst_query_add_allocation_param (query, allocator, &params);
234   gst_object_unref (allocator);
235
236   return TRUE;
237
238   /* ERRORS */
239 no_caps:
240   {
241     GST_DEBUG_OBJECT (mix, "no caps specified");
242     return FALSE;
243   }
244 invalid_caps:
245   {
246     GST_DEBUG_OBJECT (mix, "invalid caps specified");
247     return FALSE;
248   }
249 config_failed:
250   {
251     GST_DEBUG_OBJECT (mix, "failed setting config");
252     return FALSE;
253   }
254 context_error:
255   {
256     GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
257         (NULL));
258     return FALSE;
259   }
260 }
261
262 static gboolean
263 gst_gl_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
264     GstQuery * query)
265 {
266   gboolean ret = FALSE;
267   GstGLMixer *mix = GST_GL_MIXER (agg);
268
269   GST_TRACE ("QUERY %" GST_PTR_FORMAT, query);
270
271   switch (GST_QUERY_TYPE (query)) {
272     case GST_QUERY_ALLOCATION:
273     {
274       GstQuery *decide_query = NULL;
275
276       GST_OBJECT_LOCK (mix);
277       if (G_UNLIKELY (!mix->priv->negotiated)) {
278         GST_DEBUG_OBJECT (mix,
279             "not negotiated yet, can't answer ALLOCATION query");
280         GST_OBJECT_UNLOCK (mix);
281         return FALSE;
282       }
283       if ((decide_query = mix->priv->query))
284         gst_query_ref (decide_query);
285       GST_OBJECT_UNLOCK (mix);
286
287       GST_DEBUG_OBJECT (mix,
288           "calling propose allocation with query %" GST_PTR_FORMAT,
289           decide_query);
290
291       /* pass the query to the propose_allocation vmethod if any */
292       ret = gst_gl_mixer_propose_allocation (mix, decide_query, query);
293
294       if (decide_query)
295         gst_query_unref (decide_query);
296
297       GST_DEBUG_OBJECT (mix, "ALLOCATION ret %d, %" GST_PTR_FORMAT, ret, query);
298       break;
299     }
300     case GST_QUERY_CONTEXT:
301     {
302       ret = gst_gl_handle_context_query ((GstElement *) mix, query,
303           &mix->display);
304       break;
305     }
306     default:
307       ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);
308       break;
309   }
310
311   return ret;
312 }
313
314 static void
315 gst_gl_mixer_pad_init (GstGLMixerPad * mixerpad)
316 {
317 }
318
319 /* GLMixer signals and args */
320 enum
321 {
322   /* FILL ME */
323   LAST_SIGNAL
324 };
325
326 enum
327 {
328   PROP_0
329 };
330
331 static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
332     GST_PAD_SRC,
333     GST_PAD_ALWAYS,
334     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
335         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
336             "RGBA") "; "
337         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
338         (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
339             "RGBA")
340         "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
341     );
342
343 static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u",
344     GST_PAD_SINK,
345     GST_PAD_REQUEST,
346     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE_WITH_FEATURES
347         (GST_CAPS_FEATURE_MEMORY_GL_MEMORY,
348             "RGBA") "; "
349         GST_VIDEO_CAPS_MAKE_WITH_FEATURES
350         (GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
351             "RGBA")
352         "; " GST_VIDEO_CAPS_MAKE (GST_GL_COLOR_CONVERT_FORMATS))
353     );
354
355 static gboolean gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query);
356 static GstFlowReturn
357 gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator,
358     GstBuffer ** outbuf);
359 static gboolean
360 gst_gl_mixer_src_activate_mode (GstAggregator * aggregator, GstPadMode mode,
361     gboolean active);
362 static gboolean gst_gl_mixer_stop (GstAggregator * agg);
363 static gboolean gst_gl_mixer_start (GstAggregator * agg);
364
365 static GstFlowReturn
366 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg,
367     GstBuffer * outbuffer);
368
369 static void gst_gl_mixer_set_property (GObject * object, guint prop_id,
370     const GValue * value, GParamSpec * pspec);
371 static void gst_gl_mixer_get_property (GObject * object, guint prop_id,
372     GValue * value, GParamSpec * pspec);
373
374 static gboolean gst_gl_mixer_decide_allocation (GstGLMixer * mix,
375     GstQuery * query);
376 static gboolean gst_gl_mixer_set_allocation (GstGLMixer * mix,
377     GstBufferPool * pool, GstAllocator * allocator,
378     GstAllocationParams * params, GstQuery * query);
379
380 static void gst_gl_mixer_finalize (GObject * object);
381
382 static void
383 gst_gl_mixer_class_init (GstGLMixerClass * klass)
384 {
385   GObjectClass *gobject_class;
386   GstElementClass *element_class;
387
388   GstVideoAggregatorClass *videoaggregator_class =
389       (GstVideoAggregatorClass *) klass;
390   GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
391
392   GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "opengl mixer");
393
394   gobject_class = (GObjectClass *) klass;
395   element_class = GST_ELEMENT_CLASS (klass);
396
397   g_type_class_add_private (klass, sizeof (GstGLMixerPrivate));
398
399   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_gl_mixer_finalize);
400
401   gobject_class->get_property = gst_gl_mixer_get_property;
402   gobject_class->set_property = gst_gl_mixer_set_property;
403
404   gst_element_class_add_pad_template (element_class,
405       gst_static_pad_template_get (&src_factory));
406   gst_element_class_add_pad_template (element_class,
407       gst_static_pad_template_get (&sink_factory));
408
409   element_class->set_context = GST_DEBUG_FUNCPTR (gst_gl_mixer_set_context);
410
411   agg_class->sinkpads_type = GST_TYPE_GL_MIXER_PAD;
412   agg_class->sink_query = gst_gl_mixer_sink_query;
413   agg_class->src_query = gst_gl_mixer_src_query;
414   agg_class->src_activate = gst_gl_mixer_src_activate_mode;
415   agg_class->stop = gst_gl_mixer_stop;
416   agg_class->start = gst_gl_mixer_start;
417
418   videoaggregator_class->disable_frame_conversion = TRUE;
419   videoaggregator_class->aggregate_frames = gst_gl_mixer_aggregate_frames;
420   videoaggregator_class->get_output_buffer = gst_gl_mixer_get_output_buffer;
421   videoaggregator_class->negotiated_caps = _negotiated_caps;
422
423
424   /* Register the pad class */
425   g_type_class_ref (GST_TYPE_GL_MIXER_PAD);
426
427   klass->set_caps = NULL;
428
429 }
430
431 static void
432 gst_gl_mixer_reset (GstGLMixer * mix)
433 {
434   /* clean up collect data */
435   mix->priv->negotiated = FALSE;
436 }
437
438 static void
439 gst_gl_mixer_init (GstGLMixer * mix)
440 {
441   mix->priv = GST_GL_MIXER_GET_PRIVATE (mix);
442   mix->array_buffers = 0;
443   mix->display = NULL;
444   mix->fbo = 0;
445   mix->depthbuffer = 0;
446
447   mix->priv->gl_resource_ready = FALSE;
448   g_mutex_init (&mix->priv->gl_resource_lock);
449   g_cond_init (&mix->priv->gl_resource_cond);
450   /* initialize variables */
451   gst_gl_mixer_reset (mix);
452 }
453
454 static void
455 gst_gl_mixer_finalize (GObject * object)
456 {
457   GstGLMixerPrivate *priv = GST_GL_MIXER (object)->priv;
458
459   g_mutex_clear (&priv->gl_resource_lock);
460   g_cond_clear (&priv->gl_resource_cond);
461   G_OBJECT_CLASS (parent_class)->finalize (object);
462 }
463
464 static void
465 gst_gl_mixer_set_context (GstElement * element, GstContext * context)
466 {
467   GstGLMixer *mix = GST_GL_MIXER (element);
468
469   gst_gl_handle_set_context (element, context, &mix->display);
470 }
471
472 static gboolean
473 gst_gl_mixer_activate (GstGLMixer * mix, gboolean active)
474 {
475   gboolean result = TRUE;
476
477   if (active) {
478     if (!gst_gl_ensure_display (mix, &mix->display))
479       result = FALSE;
480   }
481
482   return result;
483 }
484
485 static gboolean
486 gst_gl_mixer_src_activate_mode (GstAggregator * aggregator, GstPadMode mode,
487     gboolean active)
488 {
489   GstGLMixer *mix;
490   gboolean result = FALSE;
491
492   mix = GST_GL_MIXER (aggregator);
493
494   switch (mode) {
495     case GST_PAD_MODE_PUSH:
496     case GST_PAD_MODE_PULL:
497       result = gst_gl_mixer_activate (mix, active);
498       break;
499     default:
500       result = TRUE;
501       break;
502   }
503   return result;
504 }
505
506 static gboolean
507 gst_gl_mixer_query_caps (GstPad * pad, GstAggregator * agg, GstQuery * query)
508 {
509   GstCaps *filter, *caps;
510   GstStructure *s;
511   gint n;
512
513   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
514
515   gst_query_parse_caps (query, &filter);
516
517   if (GST_VIDEO_INFO_FORMAT (&vagg->info) != GST_VIDEO_FORMAT_UNKNOWN) {
518     caps = gst_video_info_to_caps (&vagg->info);
519   } else {
520     caps = gst_pad_get_pad_template_caps (agg->srcpad);
521   }
522
523   caps = gst_caps_make_writable (caps);
524
525   n = gst_caps_get_size (caps) - 1;
526   for (; n >= 0; n--) {
527     s = gst_caps_get_structure (caps, n);
528     gst_structure_set (s, "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
529         "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, NULL);
530     if (GST_VIDEO_INFO_FPS_D (&vagg->info) != 0) {
531       gst_structure_set (s,
532           "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
533     }
534   }
535
536   if (filter)
537     caps = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
538
539   gst_query_set_caps_result (query, caps);
540   gst_caps_unref (caps);
541
542   return TRUE;
543 }
544
545 static gboolean
546 gst_gl_mixer_src_query (GstAggregator * agg, GstQuery * query)
547 {
548   gboolean res = FALSE;
549   GstGLMixer *mix = GST_GL_MIXER (agg);
550
551   switch (GST_QUERY_TYPE (query)) {
552     case GST_QUERY_CONTEXT:
553     {
554       res = gst_gl_handle_context_query ((GstElement *) mix, query,
555           &mix->display);
556       break;
557     }
558     case GST_QUERY_CAPS:
559       res = gst_gl_mixer_query_caps (agg->srcpad, agg, query);
560       break;
561     default:
562       res = GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
563       break;
564   }
565
566   return res;
567 }
568
569 static GstFlowReturn
570 gst_gl_mixer_get_output_buffer (GstVideoAggregator * videoaggregator,
571     GstBuffer ** outbuf)
572 {
573   GstGLMixer *mix = GST_GL_MIXER (videoaggregator);
574
575   if (!mix->priv->pool_active) {
576     if (!gst_buffer_pool_set_active (mix->priv->pool, TRUE)) {
577       GST_ELEMENT_ERROR (mix, RESOURCE, SETTINGS,
578           ("failed to activate bufferpool"), ("failed to activate bufferpool"));
579       return GST_FLOW_ERROR;
580     }
581     mix->priv->pool_active = TRUE;
582   }
583
584   return gst_buffer_pool_acquire_buffer (mix->priv->pool, outbuf, NULL);
585 }
586
587 static gboolean
588 gst_gl_mixer_decide_allocation (GstGLMixer * mix, GstQuery * query)
589 {
590   GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
591   GstBufferPool *pool = NULL;
592   GstStructure *config;
593   GstCaps *caps;
594   guint min, max, size;
595   gboolean update_pool;
596   GError *error = NULL;
597   guint idx;
598   guint out_width, out_height;
599   GstGLContext *other_context = NULL;
600   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
601
602   if (!gst_gl_ensure_display (mix, &mix->display))
603     return FALSE;
604
605   if (gst_query_find_allocation_meta (query,
606           GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) {
607     GstGLContext *context;
608     const GstStructure *upload_meta_params;
609     gpointer handle;
610     gchar *type;
611     gchar *apis;
612
613     gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params);
614     if (upload_meta_params) {
615       if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext",
616               GST_GL_TYPE_CONTEXT, &context, NULL) && context) {
617         GstGLContext *old = mix->context;
618
619         mix->context = context;
620         if (old)
621           gst_object_unref (old);
622       } else if (gst_structure_get (upload_meta_params, "gst.gl.context.handle",
623               G_TYPE_POINTER, &handle, "gst.gl.context.type", G_TYPE_STRING,
624               &type, "gst.gl.context.apis", G_TYPE_STRING, &apis, NULL)
625           && handle) {
626         GstGLPlatform platform;
627         GstGLAPI gl_apis;
628
629         GST_DEBUG ("got GL context handle 0x%p with type %s and apis %s",
630             handle, type, apis);
631
632         platform = gst_gl_platform_from_string (type);
633         gl_apis = gst_gl_api_from_string (apis);
634
635         if (gl_apis && platform)
636           other_context =
637               gst_gl_context_new_wrapped (mix->display, (guintptr) handle,
638               platform, gl_apis);
639       }
640     }
641   }
642
643   if (!mix->context) {
644     mix->context = gst_gl_context_new (mix->display);
645     if (!gst_gl_context_create (mix->context, other_context, &error))
646       goto context_error;
647   }
648
649   out_width = GST_VIDEO_INFO_WIDTH (&vagg->info);
650   out_height = GST_VIDEO_INFO_HEIGHT (&vagg->info);
651
652   g_mutex_lock (&mix->priv->gl_resource_lock);
653   mix->priv->gl_resource_ready = FALSE;
654   if (mix->fbo) {
655     gst_gl_context_del_fbo (mix->context, mix->fbo, mix->depthbuffer);
656     mix->fbo = 0;
657     mix->depthbuffer = 0;
658   }
659
660   if (!gst_gl_context_gen_fbo (mix->context, out_width, out_height,
661           &mix->fbo, &mix->depthbuffer)) {
662     g_cond_signal (&mix->priv->gl_resource_cond);
663     g_mutex_unlock (&mix->priv->gl_resource_lock);
664     goto context_error;
665   }
666
667   if (mix->out_tex_id)
668     gst_gl_context_del_texture (mix->context, &mix->out_tex_id);
669   gst_gl_context_gen_texture (mix->context, &mix->out_tex_id,
670       GST_VIDEO_FORMAT_RGBA, out_width, out_height);
671
672   gst_query_parse_allocation (query, &caps, NULL);
673
674   if (mixer_class->set_caps)
675     mixer_class->set_caps (mix, caps);
676
677   mix->priv->gl_resource_ready = TRUE;
678   g_cond_signal (&mix->priv->gl_resource_cond);
679   g_mutex_unlock (&mix->priv->gl_resource_lock);
680
681   if (gst_query_get_n_allocation_pools (query) > 0) {
682     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
683
684     update_pool = TRUE;
685   } else {
686     GstVideoInfo vinfo;
687
688     gst_video_info_init (&vinfo);
689     gst_video_info_from_caps (&vinfo, caps);
690     size = vinfo.size;
691     min = max = 0;
692     update_pool = FALSE;
693   }
694
695   if (!pool)
696     pool = gst_gl_buffer_pool_new (mix->context);
697
698   config = gst_buffer_pool_get_config (pool);
699   gst_buffer_pool_config_set_params (config, caps, size, min, max);
700
701   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
702
703   gst_buffer_pool_set_config (pool, config);
704
705   if (update_pool)
706     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
707   else
708     gst_query_add_allocation_pool (query, pool, size, min, max);
709
710   gst_object_unref (pool);
711
712   return TRUE;
713
714 context_error:
715   {
716     GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
717         (NULL));
718     return FALSE;
719   }
720 }
721
722 /* takes ownership of the pool, allocator and query */
723 static gboolean
724 gst_gl_mixer_set_allocation (GstGLMixer * mix,
725     GstBufferPool * pool, GstAllocator * allocator,
726     GstAllocationParams * params, GstQuery * query)
727 {
728   GstAllocator *oldalloc;
729   GstBufferPool *oldpool;
730   GstQuery *oldquery;
731   GstGLMixerPrivate *priv = mix->priv;
732
733   GST_DEBUG ("storing allocation query");
734
735   GST_OBJECT_LOCK (mix);
736   oldpool = priv->pool;
737   priv->pool = pool;
738   priv->pool_active = FALSE;
739
740   oldalloc = priv->allocator;
741   priv->allocator = allocator;
742
743   oldquery = priv->query;
744   priv->query = query;
745
746   if (params)
747     priv->params = *params;
748   else
749     gst_allocation_params_init (&priv->params);
750   GST_OBJECT_UNLOCK (mix);
751
752   if (oldpool) {
753     GST_DEBUG_OBJECT (mix, "deactivating old pool %p", oldpool);
754     gst_buffer_pool_set_active (oldpool, FALSE);
755     gst_object_unref (oldpool);
756   }
757   if (oldalloc) {
758     gst_object_unref (oldalloc);
759   }
760   if (oldquery) {
761     gst_query_unref (oldquery);
762   }
763   return TRUE;
764 }
765
766 static gboolean
767 gst_gl_mixer_do_bufferpool (GstGLMixer * mix, GstCaps * outcaps)
768 {
769   GstQuery *query;
770   gboolean result = TRUE;
771   GstBufferPool *pool = NULL;
772   GstAllocator *allocator;
773   GstAllocationParams params;
774   GstAggregator *agg = GST_AGGREGATOR (mix);
775
776   /* find a pool for the negotiated caps now */
777   GST_DEBUG_OBJECT (mix, "doing allocation query");
778   query = gst_query_new_allocation (outcaps, TRUE);
779   if (!gst_pad_peer_query (agg->srcpad, query)) {
780     /* not a problem, just debug a little */
781     GST_DEBUG_OBJECT (mix, "peer ALLOCATION query failed");
782   }
783
784   GST_DEBUG_OBJECT (mix, "calling decide_allocation");
785   result = gst_gl_mixer_decide_allocation (mix, query);
786
787   GST_DEBUG_OBJECT (mix, "ALLOCATION (%d) params: %" GST_PTR_FORMAT, result,
788       query);
789
790   if (!result)
791     goto no_decide_allocation;
792
793   /* we got configuration from our peer or the decide_allocation method,
794    * parse them */
795   if (gst_query_get_n_allocation_params (query) > 0) {
796     gst_query_parse_nth_allocation_param (query, 0, &allocator, &params);
797   } else {
798     allocator = NULL;
799     gst_allocation_params_init (&params);
800   }
801
802   if (gst_query_get_n_allocation_pools (query) > 0)
803     gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL);
804
805   /* now store */
806   result = gst_gl_mixer_set_allocation (mix, pool, allocator, &params, query);
807
808   return result;
809
810   /* Errors */
811 no_decide_allocation:
812   {
813     GST_WARNING_OBJECT (mix, "Failed to decide allocation");
814     gst_query_unref (query);
815
816     return result;
817   }
818 }
819
820 gboolean
821 gst_gl_mixer_process_textures (GstGLMixer * mix, GstBuffer * outbuf)
822 {
823   guint i;
824   GList *walk;
825   guint out_tex;
826   gboolean res = TRUE;
827   guint array_index = 0;
828   GstVideoFrame out_frame;
829   gboolean out_gl_wrapped = FALSE;
830   GstElement *element = GST_ELEMENT (mix);
831   GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (mix);
832   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
833   GstGLMixerPrivate *priv = mix->priv;
834
835   GST_TRACE ("Processing buffers");
836
837   if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf,
838           GST_MAP_WRITE | GST_MAP_GL)) {
839     return FALSE;
840   }
841
842   if (gst_is_gl_memory (out_frame.map[0].memory)) {
843     out_tex = *(guint *) out_frame.data[0];
844   } else {
845     GST_INFO ("Output Buffer does not contain correct memory, "
846         "attempting to wrap for download");
847
848     out_tex = mix->out_tex_id;;
849
850     if (!mix->download)
851       mix->download = gst_gl_download_new (mix->context);
852
853     gst_gl_download_set_format (mix->download, &out_frame.info);
854     out_gl_wrapped = TRUE;
855   }
856
857   GST_OBJECT_LOCK (mix);
858   walk = element->sinkpads;
859
860   i = mix->frames->len;
861   g_ptr_array_set_size (mix->frames, element->numsinkpads);
862   for (; i < element->numsinkpads; i++)
863     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
864   while (walk) {
865     GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data);
866     GstVideoAggregatorPad *vaggpad = walk->data;
867     GstGLMixerFrameData *frame;
868
869     frame = g_ptr_array_index (mix->frames, array_index);
870     frame->pad = pad;
871     frame->texture = 0;
872
873     walk = g_list_next (walk);
874
875     if (vaggpad->buffer != NULL) {
876       guint in_tex;
877
878       if (!pad->upload) {
879         pad->upload = gst_gl_upload_new (mix->context);
880
881         gst_gl_upload_set_format (pad->upload, &vaggpad->info);
882       }
883
884       if (!gst_gl_upload_perform_with_buffer (pad->upload,
885               vaggpad->buffer, &in_tex)) {
886         ++array_index;
887         pad->mapped = FALSE;
888         continue;
889       }
890       pad->mapped = TRUE;
891
892       frame->texture = in_tex;
893     }
894     ++array_index;
895   }
896
897   g_mutex_lock (&priv->gl_resource_lock);
898   if (!priv->gl_resource_ready)
899     g_cond_wait (&priv->gl_resource_cond, &priv->gl_resource_lock);
900
901   if (!priv->gl_resource_ready) {
902     g_mutex_unlock (&priv->gl_resource_lock);
903     GST_ERROR_OBJECT (mix,
904         "fbo used to render can't be created, do not run process_textures");
905     res = FALSE;
906     goto out;
907   }
908
909   mix_class->process_textures (mix, mix->frames, out_tex);
910
911   g_mutex_unlock (&priv->gl_resource_lock);
912
913   if (out_gl_wrapped) {
914     if (!gst_gl_download_perform_with_data (mix->download, out_tex,
915             out_frame.data)) {
916       GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s",
917               "Failed to download video frame"), (NULL));
918       res = FALSE;
919       goto out;
920     }
921   }
922
923 out:
924   i = 0;
925   walk = GST_ELEMENT (mix)->sinkpads;
926   while (walk) {
927     GstGLMixerPad *pad = GST_GL_MIXER_PAD (walk->data);
928
929     if (pad->mapped)
930       gst_gl_upload_release_buffer (pad->upload);
931
932     pad->mapped = FALSE;
933     walk = g_list_next (walk);
934     i++;
935   }
936   GST_OBJECT_UNLOCK (mix);
937
938   gst_video_frame_unmap (&out_frame);
939
940   return res;
941 }
942
943 static gboolean
944 gst_gl_mixer_process_buffers (GstGLMixer * mix, GstBuffer * outbuf)
945 {
946   GList *walk;
947   guint i, array_index = 0;
948   GstElement *element = GST_ELEMENT (mix);
949   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (mix);
950
951   GST_OBJECT_LOCK (mix);
952   walk = GST_ELEMENT (mix)->sinkpads;
953   i = mix->frames->len;
954   g_ptr_array_set_size (mix->frames, element->numsinkpads);
955   for (; i < element->numsinkpads; i++)
956     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
957   while (walk) {                /* We walk with this list because it's ordered */
958     GstVideoAggregatorPad *vaggpad = walk->data;
959
960     walk = g_list_next (walk);
961
962     if (vaggpad->buffer != NULL) {
963       /* put buffer into array */
964       mix->array_buffers->pdata[array_index] = vaggpad->buffer;
965     }
966     ++array_index;
967   }
968   GST_OBJECT_UNLOCK (mix);
969
970   return mix_class->process_buffers (mix, mix->array_buffers, outbuf);
971 }
972
973
974
975 static GstFlowReturn
976 gst_gl_mixer_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
977 {
978   gboolean res = FALSE;
979   GstGLMixer *mix = GST_GL_MIXER (vagg);
980   GstGLMixerClass *mix_class = GST_GL_MIXER_GET_CLASS (vagg);
981
982   if (mix_class->process_buffers)
983     res = gst_gl_mixer_process_buffers (mix, outbuf);
984   else if (mix_class->process_textures)
985     res = gst_gl_mixer_process_textures (mix, outbuf);
986
987   return res ? GST_FLOW_OK : GST_FLOW_ERROR;
988 }
989
990 static void
991 gst_gl_mixer_get_property (GObject * object,
992     guint prop_id, GValue * value, GParamSpec * pspec)
993 {
994   switch (prop_id) {
995     default:
996       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
997       break;
998   }
999 }
1000
1001 static void
1002 gst_gl_mixer_set_property (GObject * object,
1003     guint prop_id, const GValue * value, GParamSpec * pspec)
1004 {
1005   switch (prop_id) {
1006     default:
1007       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1008       break;
1009   }
1010 }
1011
1012 static gboolean
1013 _clean_upload (GstAggregator * agg, GstPad * aggpad, gpointer udata)
1014 {
1015   GstGLMixerPad *pad = GST_GL_MIXER_PAD (aggpad);
1016
1017   if (pad->upload) {
1018     gst_object_unref (pad->upload);
1019     pad->upload = NULL;
1020   }
1021
1022   return TRUE;
1023 }
1024
1025 static void
1026 _free_glmixer_frame_data (GstGLMixerFrameData * frame)
1027 {
1028   g_slice_free1 (sizeof (GstGLMixerFrameData), frame);
1029 }
1030
1031 static gboolean
1032 gst_gl_mixer_start (GstAggregator * agg)
1033 {
1034   guint i;
1035   GstGLMixer *mix = GST_GL_MIXER (agg);
1036   GstElement *element = GST_ELEMENT (agg);
1037
1038   if (!GST_AGGREGATOR_CLASS (parent_class)->start (agg))
1039     return FALSE;
1040
1041   GST_OBJECT_LOCK (mix);
1042   mix->array_buffers = g_ptr_array_new_full (element->numsinkpads,
1043       (GDestroyNotify) _free_glmixer_frame_data);
1044   mix->frames = g_ptr_array_new_full (element->numsinkpads, NULL);
1045
1046   g_ptr_array_set_size (mix->array_buffers, element->numsinkpads);
1047   g_ptr_array_set_size (mix->frames, element->numsinkpads);
1048
1049   for (i = 0; i < element->numsinkpads; i++)
1050     mix->frames->pdata[i] = g_slice_new0 (GstGLMixerFrameData);
1051
1052   GST_OBJECT_UNLOCK (mix);
1053
1054   return TRUE;
1055 }
1056
1057 static gboolean
1058 gst_gl_mixer_stop (GstAggregator * agg)
1059 {
1060   GstGLMixer *mix = GST_GL_MIXER (agg);
1061   GstGLMixerClass *mixer_class = GST_GL_MIXER_GET_CLASS (mix);
1062
1063   if (!GST_AGGREGATOR_CLASS (parent_class)->stop (agg))
1064     return FALSE;
1065
1066   GST_OBJECT_LOCK (agg);
1067   g_ptr_array_free (mix->frames, TRUE);
1068   mix->frames = NULL;
1069   g_ptr_array_free (mix->array_buffers, TRUE);
1070   mix->array_buffers = NULL;
1071   GST_OBJECT_UNLOCK (agg);
1072
1073   if (mixer_class->reset)
1074     mixer_class->reset (mix);
1075   if (mix->fbo) {
1076     gst_gl_context_del_fbo (mix->context, mix->fbo, mix->depthbuffer);
1077     mix->fbo = 0;
1078     mix->depthbuffer = 0;
1079   }
1080   if (mix->download) {
1081     gst_object_unref (mix->download);
1082     mix->download = NULL;
1083   }
1084
1085   gst_aggregator_iterate_sinkpads (GST_AGGREGATOR (mix), _clean_upload, NULL);
1086
1087   if (mix->priv->query) {
1088     gst_query_unref (mix->priv->query);
1089     mix->priv->query = NULL;
1090   }
1091
1092   if (mix->priv->pool) {
1093     gst_object_unref (mix->priv->pool);
1094     mix->priv->pool = NULL;
1095   }
1096
1097   if (mix->display) {
1098     gst_object_unref (mix->display);
1099     mix->display = NULL;
1100   }
1101
1102   if (mix->context) {
1103     gst_object_unref (mix->context);
1104     mix->context = NULL;
1105   }
1106   gst_gl_mixer_reset (mix);
1107
1108   return TRUE;
1109 }