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