3b9a829a3598cab665cf820536b336bb18071028
[platform/upstream/gstreamer.git] / gst-libs / gst / gl / gstglutils.c
1 /* 
2  * GStreamer
3  * Copyright (C) 2013 Matthew Waters <ystreet00@gmail.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdio.h>
25
26 #include <gst/gst.h>
27
28 #include "gl.h"
29 #include "gstglutils.h"
30
31 #if GST_GL_HAVE_WINDOW_X11
32 #include <gst/gl/x11/gstgldisplay_x11.h>
33 #endif
34
35 #ifndef GL_FRAMEBUFFER_UNDEFINED
36 #define GL_FRAMEBUFFER_UNDEFINED          0x8219
37 #endif
38 #ifndef GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
39 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
40 #endif
41 #ifndef GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
42 #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
43 #endif
44 #ifndef GL_FRAMEBUFFER_UNSUPPORTED
45 #define GL_FRAMEBUFFER_UNSUPPORTED        0x8CDD
46 #endif
47 #ifndef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
48 #define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
49 #endif
50
51 #define USING_OPENGL(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL, 1, 0))
52 #define USING_OPENGL3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_OPENGL3, 3, 1))
53 #define USING_GLES(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES, 1, 0))
54 #define USING_GLES2(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 2, 0))
55 #define USING_GLES3(context) (gst_gl_context_check_gl_version (context, GST_GL_API_GLES2, 3, 0))
56
57 static gchar *error_message;
58
59 /* called in the gl thread */
60 gboolean
61 gst_gl_context_check_framebuffer_status (GstGLContext * context)
62 {
63   GLenum status = 0;
64   status = context->gl_vtable->CheckFramebufferStatus (GL_FRAMEBUFFER);
65
66   switch (status) {
67     case GL_FRAMEBUFFER_COMPLETE:
68       return TRUE;
69       break;
70
71     case GL_FRAMEBUFFER_UNSUPPORTED:
72       GST_ERROR ("GL_FRAMEBUFFER_UNSUPPORTED");
73       break;
74
75     case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
76       GST_ERROR ("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
77       break;
78
79     case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
80       GST_ERROR ("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
81       break;
82     case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
83       GST_ERROR ("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
84       break;
85 #if GST_GL_HAVE_OPENGL
86     case GL_FRAMEBUFFER_UNDEFINED:
87       GST_ERROR ("GL_FRAMEBUFFER_UNDEFINED");
88       break;
89 #endif
90     default:
91       GST_ERROR ("General FBO error");
92   }
93
94   return FALSE;
95 }
96
97 typedef struct _GenTexture
98 {
99   guint width, height;
100   GstVideoFormat format;
101   guint result;
102 } GenTexture;
103
104 static void
105 _gen_texture (GstGLContext * context, GenTexture * data)
106 {
107   const GstGLFuncs *gl = context->gl_vtable;
108
109   GST_TRACE ("Generating texture format:%u dimensions:%ux%u", data->format,
110       data->width, data->height);
111
112   gl->GenTextures (1, &data->result);
113   gl->BindTexture (GL_TEXTURE_2D, data->result);
114
115   if (data->width > 0 && data->height > 0)
116     gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, data->width,
117         data->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
118
119   gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
120   gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
121   gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
122   gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
123
124   GST_LOG ("generated texture id:%d", data->result);
125 }
126
127 void
128 gst_gl_context_gen_texture (GstGLContext * context, GLuint * pTexture,
129     GstVideoFormat v_format, GLint width, GLint height)
130 {
131   GenTexture data = { width, height, v_format, 0 };
132
133   gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _gen_texture,
134       &data);
135
136   *pTexture = data.result;
137 }
138
139 static void
140 _del_texture (GstGLContext * context, guint * texture)
141 {
142   context->gl_vtable->DeleteTextures (1, texture);
143 }
144
145 void
146 gst_gl_context_del_texture (GstGLContext * context, GLuint * pTexture)
147 {
148   gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _del_texture,
149       pTexture);
150 }
151
152 typedef struct _GenTextureFull
153 {
154   const GstVideoInfo *info;
155   const gint comp;
156   guint result;
157 } GenTextureFull;
158
159 static void
160 _gen_texture_full (GstGLContext * context, GenTextureFull * data)
161 {
162   const GstGLFuncs *gl = context->gl_vtable;
163   GLint glinternalformat = 0;
164   GLenum glformat = 0;
165   GLenum gltype = 0;
166
167   gl->GenTextures (1, &data->result);
168   gl->BindTexture (GL_TEXTURE_2D, data->result);
169
170   switch (GST_VIDEO_INFO_FORMAT (data->info)) {
171     case GST_VIDEO_FORMAT_RGB:
172     case GST_VIDEO_FORMAT_BGR:
173     {
174       glinternalformat = GL_RGB8;
175       glformat = GL_RGB;
176       gltype = GL_UNSIGNED_BYTE;
177       break;
178     }
179     case GST_VIDEO_FORMAT_RGB16:
180     {
181       glinternalformat = GL_RGB16;
182       glformat = GL_RGB;
183       gltype = GL_UNSIGNED_SHORT_5_6_5;
184       break;
185     }
186     case GST_VIDEO_FORMAT_RGBA:
187     case GST_VIDEO_FORMAT_BGRA:
188     case GST_VIDEO_FORMAT_ARGB:
189     case GST_VIDEO_FORMAT_ABGR:
190     case GST_VIDEO_FORMAT_RGBx:
191     case GST_VIDEO_FORMAT_BGRx:
192     case GST_VIDEO_FORMAT_xRGB:
193     case GST_VIDEO_FORMAT_xBGR:
194     case GST_VIDEO_FORMAT_AYUV:
195     {
196       glinternalformat = GL_RGBA8;
197       glformat = GL_RGBA;
198       gltype = GL_UNSIGNED_BYTE;
199       break;
200     }
201     case GST_VIDEO_FORMAT_NV12:
202     case GST_VIDEO_FORMAT_NV21:
203     {
204       glinternalformat = GL_LUMINANCE;
205       glformat = data->comp == 0 ? GL_LUMINANCE : GL_LUMINANCE_ALPHA;
206       gltype = GL_UNSIGNED_BYTE;
207       break;
208     }
209     case GST_VIDEO_FORMAT_I420:
210     case GST_VIDEO_FORMAT_YV12:
211     case GST_VIDEO_FORMAT_Y444:
212     case GST_VIDEO_FORMAT_Y42B:
213     case GST_VIDEO_FORMAT_Y41B:
214     {
215       glformat = GL_LUMINANCE;
216       gltype = GL_UNSIGNED_BYTE;
217       break;
218     }
219     default:
220       GST_WARNING ("unsupported %s",
221           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (data->info)));
222       break;
223   }
224
225   gl->TexImage2D (GL_TEXTURE_2D, 0, glinternalformat,
226       GST_VIDEO_INFO_COMP_WIDTH (data->info, data->comp),
227       GST_VIDEO_INFO_COMP_HEIGHT (data->info, data->comp), 0, glformat, gltype,
228       NULL);
229
230   gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
231   gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
232   gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
233   gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
234 }
235
236 void
237 gst_gl_generate_texture_full (GstGLContext * context, const GstVideoInfo * info,
238     const guint comp, gint stride[], gsize offset[], gsize size[],
239     GLuint * pTexture)
240 {
241   GenTextureFull data = { info, comp, 0 };
242
243   switch (GST_VIDEO_INFO_FORMAT (info)) {
244     case GST_VIDEO_FORMAT_RGB:
245     case GST_VIDEO_FORMAT_BGR:
246     {
247       stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (info) * 3);
248       offset[0] = 0;
249       size[0] = stride[0] * GST_VIDEO_INFO_HEIGHT (info);
250       break;
251     }
252     case GST_VIDEO_FORMAT_RGB16:
253     {
254       stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (info) * 2);
255       offset[0] = 0;
256       size[0] = stride[0] * GST_VIDEO_INFO_HEIGHT (info);
257       break;
258     }
259     case GST_VIDEO_FORMAT_RGBA:
260     case GST_VIDEO_FORMAT_BGRA:
261     case GST_VIDEO_FORMAT_ARGB:
262     case GST_VIDEO_FORMAT_ABGR:
263     case GST_VIDEO_FORMAT_RGBx:
264     case GST_VIDEO_FORMAT_BGRx:
265     case GST_VIDEO_FORMAT_xRGB:
266     case GST_VIDEO_FORMAT_xBGR:
267     case GST_VIDEO_FORMAT_AYUV:
268     {
269       stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (info) * 4);
270       offset[0] = 0;
271       size[0] = stride[0] * GST_VIDEO_INFO_HEIGHT (info);
272       break;
273     }
274     case GST_VIDEO_FORMAT_NV12:
275     case GST_VIDEO_FORMAT_NV21:
276     {
277       size[comp] = stride[comp] * GST_VIDEO_INFO_COMP_HEIGHT (info, comp);
278       if (comp == 0) {
279         stride[0] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (info, 1));
280         offset[0] = 0;
281       } else {
282         stride[1] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (info, 1) * 2);
283         offset[1] = size[0];
284       }
285       break;
286     }
287     case GST_VIDEO_FORMAT_I420:
288     case GST_VIDEO_FORMAT_YV12:
289     case GST_VIDEO_FORMAT_Y444:
290     case GST_VIDEO_FORMAT_Y42B:
291     case GST_VIDEO_FORMAT_Y41B:
292     {
293       stride[comp] = GST_ROUND_UP_4 (GST_VIDEO_INFO_COMP_WIDTH (info, comp));;
294       size[comp] = stride[comp] * GST_VIDEO_INFO_COMP_HEIGHT (info, comp);
295       if (comp == 0)
296         offset[0] = 0;
297       else if (comp == 1)
298         offset[1] = size[0];
299       else
300         offset[2] = offset[1] + size[1];
301       break;
302     }
303     default:
304       GST_WARNING ("unsupported %s",
305           gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (info)));
306       break;
307   }
308
309   gst_gl_context_thread_add (context,
310       (GstGLContextThreadFunc) _gen_texture_full, &data);
311
312   *pTexture = data.result;
313 }
314
315 typedef struct _GenFBO
316 {
317   GstGLFramebuffer *frame;
318   gint width, height;
319   GLuint *fbo, *depth;
320 } GenFBO;
321
322 static void
323 _gen_fbo (GstGLContext * context, GenFBO * data)
324 {
325   gst_gl_framebuffer_generate (data->frame, data->width, data->height,
326       data->fbo, data->depth);
327 }
328
329 gboolean
330 gst_gl_context_gen_fbo (GstGLContext * context, gint width, gint height,
331     GLuint * fbo, GLuint * depthbuffer)
332 {
333   GstGLFramebuffer *frame = gst_gl_framebuffer_new (context);
334
335   GenFBO data = { frame, width, height, fbo, depthbuffer };
336
337   gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _gen_fbo, &data);
338
339   gst_object_unref (frame);
340
341   return TRUE;
342 }
343
344 typedef struct _UseFBO2
345 {
346   GstGLFramebuffer *frame;
347   gint texture_fbo_width;
348   gint texture_fbo_height;
349   GLuint fbo;
350   GLuint depth_buffer;
351   GLuint texture_fbo;
352   GLCB_V2 cb;
353   gpointer stuff;
354 } UseFBO2;
355
356 static void
357 _use_fbo_v2 (GstGLContext * context, UseFBO2 * data)
358 {
359   gst_gl_framebuffer_use_v2 (data->frame, data->texture_fbo_width,
360       data->texture_fbo_height, data->fbo, data->depth_buffer,
361       data->texture_fbo, data->cb, data->stuff);
362 }
363
364 gboolean
365 gst_gl_context_use_fbo_v2 (GstGLContext * context, gint texture_fbo_width,
366     gint texture_fbo_height, GLuint fbo, GLuint depth_buffer,
367     GLuint texture_fbo, GLCB_V2 cb, gpointer stuff)
368 {
369   GstGLFramebuffer *frame = gst_gl_framebuffer_new (context);
370
371   UseFBO2 data =
372       { frame, texture_fbo_width, texture_fbo_height, fbo, depth_buffer,
373     texture_fbo, cb, stuff
374   };
375
376   gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _use_fbo_v2,
377       &data);
378
379   gst_object_unref (frame);
380
381   return TRUE;
382 }
383
384 typedef struct _DelFBO
385 {
386   GstGLFramebuffer *frame;
387   GLuint fbo;
388   GLuint depth;
389 } DelFBO;
390
391 /* Called in the gl thread */
392 static void
393 _del_fbo (GstGLContext * context, DelFBO * data)
394 {
395   gst_gl_framebuffer_delete (data->frame, data->fbo, data->depth);
396 }
397
398 /* Called by gltestsrc and glfilter */
399 void
400 gst_gl_context_del_fbo (GstGLContext * context, GLuint fbo, GLuint depth_buffer)
401 {
402   GstGLFramebuffer *frame = gst_gl_framebuffer_new (context);
403
404   DelFBO data = { frame, fbo, depth_buffer };
405
406   gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _del_fbo, &data);
407
408   gst_object_unref (frame);
409 }
410
411 static void
412 _compile_shader (GstGLContext * context, GstGLShader ** shader)
413 {
414   GError *error = NULL;
415
416   gst_gl_shader_compile (*shader, &error);
417   if (error) {
418     gst_gl_context_set_error (context, "%s", error->message);
419     g_error_free (error);
420     error = NULL;
421     gst_gl_context_clear_shader (context);
422     gst_object_unref (*shader);
423     *shader = NULL;
424   }
425 }
426
427 /* Called by glfilter */
428 gboolean
429 gst_gl_context_gen_shader (GstGLContext * context, const gchar * vert_src,
430     const gchar * frag_src, GstGLShader ** shader)
431 {
432   g_return_val_if_fail (frag_src != NULL || vert_src != NULL, FALSE);
433   g_return_val_if_fail (shader != NULL, FALSE);
434
435   *shader = gst_gl_shader_new (context);
436
437   if (frag_src)
438     gst_gl_shader_set_fragment_source (*shader, frag_src);
439   if (vert_src)
440     gst_gl_shader_set_vertex_source (*shader, vert_src);
441
442   gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _compile_shader,
443       shader);
444
445   return *shader != NULL;
446 }
447
448 void
449 gst_gl_context_set_error (GstGLContext * context, const char *format, ...)
450 {
451   va_list args;
452
453   if (error_message)
454     g_free (error_message);
455
456   va_start (args, format);
457   error_message = g_strdup_vprintf (format, args);
458   va_end (args);
459
460   GST_WARNING ("%s", error_message);
461 }
462
463 gchar *
464 gst_gl_context_get_error (void)
465 {
466   return error_message;
467 }
468
469 /* Called by glfilter */
470 void
471 gst_gl_context_del_shader (GstGLContext * context, GstGLShader * shader)
472 {
473   gst_object_unref (shader);
474 }
475
476 static gboolean
477 gst_gl_display_found (GstElement * element, GstGLDisplay * display)
478 {
479   if (display) {
480     GST_LOG_OBJECT (element, "already have a display (%p)", display);
481     return TRUE;
482   }
483
484   return FALSE;
485 }
486
487 GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
488
489 static gboolean
490 context_pad_query (const GValue * item, GValue * value, gpointer user_data)
491 {
492   GstPad *pad = g_value_get_object (item);
493   GstQuery *query = user_data;
494   gboolean res;
495
496   res = gst_pad_peer_query (pad, query);
497
498   if (res) {
499     g_value_set_boolean (value, TRUE);
500     return FALSE;
501   }
502
503   GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "context pad peer query failed");
504   return TRUE;
505 }
506
507 static gboolean
508 run_context_query (GstElement * element, GstQuery * query,
509     GstPadDirection direction)
510 {
511   GstIterator *it;
512   GstIteratorFoldFunction func = context_pad_query;
513   GValue res = { 0 };
514
515   g_value_init (&res, G_TYPE_BOOLEAN);
516   g_value_set_boolean (&res, FALSE);
517
518   /* Ask neighbor */
519   if (direction == GST_PAD_SRC)
520     it = gst_element_iterate_src_pads (element);
521   else
522     it = gst_element_iterate_sink_pads (element);
523
524   while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
525     gst_iterator_resync (it);
526
527   gst_iterator_free (it);
528
529   return g_value_get_boolean (&res);
530 }
531
532 static GstQuery *
533 _gst_context_query (GstElement * element,
534     gpointer ptr, const gchar * display_type)
535 {
536   GstQuery *query;
537   GstContext *ctxt;
538
539   /*  2a) Query downstream with GST_QUERY_CONTEXT for the context and
540    *      check if downstream already has a context of the specific type
541    *  2b) Query upstream as above.
542    */
543   query = gst_query_new_context (display_type);
544   if (run_context_query (element, query, GST_PAD_SRC)) {
545     gst_query_parse_context (query, &ctxt);
546     GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
547         "found context (%p) in downstream query", ctxt);
548   } else if (run_context_query (element, query, GST_PAD_SINK)) {
549     gst_query_parse_context (query, &ctxt);
550     GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
551         "found context (%p) in upstream query", ctxt);
552   } else {
553     /* 3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
554      *    the required context type and afterwards check if a
555      *    usable context was set now as in 1). The message could
556      *    be handled by the parent bins of the element and the
557      *    application.
558      */
559     GstMessage *msg;
560
561     GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
562         "posting need context message");
563     msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
564         display_type);
565     gst_element_post_message (element, msg);
566   }
567
568   /*
569    * Whomever responds to the need-context message performs a
570    * GstElement::set_context() with the required context in which the element
571    * is required to update the display_ptr or call gst_gl_handle_set_context().
572    */
573
574   return query;
575 }
576
577 static void
578 gst_gl_display_context_query (GstElement * element, GstGLDisplay ** display_ptr)
579 {
580   GstContext *ctxt;
581   GstQuery *query;
582
583 #ifndef GST_DISABLE_GST_DEBUG
584   if (!GST_CAT_CONTEXT)
585     GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
586 #endif
587
588   query =
589       _gst_context_query (element, display_ptr, GST_GL_DISPLAY_CONTEXT_TYPE);
590   gst_query_parse_context (query, &ctxt);
591   if (ctxt && gst_context_has_context_type (ctxt, GST_GL_DISPLAY_CONTEXT_TYPE))
592     gst_context_get_gl_display (ctxt, display_ptr);
593
594   if (*display_ptr)
595     goto out;
596
597 #if GST_GL_HAVE_WINDOW_X11
598   gst_query_unref (query);
599   query = _gst_context_query (element, display_ptr, "gst.x11.display.handle");
600   gst_query_parse_context (query, &ctxt);
601   if (ctxt && gst_context_has_context_type (ctxt, "gst.x11.display.handle")) {
602     const GstStructure *s;
603     Display *display;
604
605     s = gst_context_get_structure (ctxt);
606     if (gst_structure_get (s, "display", G_TYPE_POINTER, &display, NULL)
607         && display) {
608       *display_ptr =
609           (GstGLDisplay *) gst_gl_display_x11_new_with_display (display);
610     }
611   }
612
613   if (*display_ptr)
614     goto out;
615 #endif
616
617 out:
618   gst_query_unref (query);
619 }
620
621 static void
622 gst_gl_context_query (GstElement * element, GstGLContext ** context_ptr)
623 {
624   GstContext *ctxt;
625   GstQuery *query;
626
627 #ifndef GST_DISABLE_GST_DEBUG
628   if (!GST_CAT_CONTEXT)
629     GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
630 #endif
631
632   query = _gst_context_query (element, context_ptr, "gst.gl.app_context");
633   gst_query_parse_context (query, &ctxt);
634   if (ctxt && gst_context_has_context_type (ctxt, "gst.gl.app_context")) {
635     const GstStructure *s = gst_context_get_structure (ctxt);
636     gst_structure_get (s, "context", GST_GL_TYPE_CONTEXT, context_ptr, NULL);
637   }
638
639   gst_query_unref (query);
640 }
641
642 /*  4) Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT
643  *     message.
644  */
645 static void
646 gst_gl_display_context_propagate (GstElement * element, GstGLDisplay * display)
647 {
648   GstContext *context;
649   GstMessage *msg;
650
651   if (!display) {
652     GST_ERROR_OBJECT (element, "Could not get GL display connection");
653     return;
654   }
655
656   context = gst_context_new (GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
657   gst_context_set_gl_display (context, display);
658
659   GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
660       "posting have context (%p) message with display (%p)", context, display);
661   msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
662   gst_element_post_message (GST_ELEMENT_CAST (element), msg);
663 }
664
665 gboolean
666 gst_gl_ensure_element_data (gpointer element, GstGLDisplay ** display_ptr,
667     GstGLContext ** context_ptr)
668 {
669   GstGLDisplay *display;
670
671   g_return_val_if_fail (element != NULL, FALSE);
672   g_return_val_if_fail (display_ptr != NULL, FALSE);
673   g_return_val_if_fail (context_ptr != NULL, FALSE);
674
675   /*  1) Check if the element already has a context of the specific
676    *     type.
677    */
678   display = *display_ptr;
679   if (gst_gl_display_found (element, display))
680     goto done;
681
682   gst_gl_display_context_query (element, display_ptr);
683
684   /* Neighbour found and it updated the display */
685   if (gst_gl_display_found (element, *display_ptr))
686     goto get_gl_context;
687
688   /* If no neighboor, or application not interested, use system default */
689   display = gst_gl_display_new ();
690
691   *display_ptr = display;
692
693   gst_gl_display_context_propagate (element, display);
694
695 get_gl_context:
696   if (*context_ptr)
697     goto done;
698
699   gst_gl_context_query (element, context_ptr);
700
701 done:
702   return *display_ptr != NULL;
703 }
704
705 gboolean
706 gst_gl_handle_set_context (GstElement * element, GstContext * context,
707     GstGLDisplay ** display, GstGLContext ** other_context)
708 {
709   GstGLDisplay *display_replacement = NULL;
710   GstGLContext *context_replacement = NULL;
711   const gchar *context_type;
712
713   g_return_val_if_fail (display != NULL, FALSE);
714   g_return_val_if_fail (other_context != NULL, FALSE);
715
716   if (!context)
717     return FALSE;
718
719   context_type = gst_context_get_context_type (context);
720
721   if (g_strcmp0 (context_type, GST_GL_DISPLAY_CONTEXT_TYPE) == 0) {
722     if (!gst_context_get_gl_display (context, &display_replacement)) {
723       GST_WARNING_OBJECT (element, "Failed to get display from context");
724       return FALSE;
725     }
726   }
727 #if GST_GL_HAVE_WINDOW_X11
728   else if (g_strcmp0 (context_type, "gst.x11.display.handle") == 0) {
729     const GstStructure *s;
730     Display *display;
731
732     s = gst_context_get_structure (context);
733     if (gst_structure_get (s, "display", G_TYPE_POINTER, &display, NULL))
734       display_replacement =
735           (GstGLDisplay *) gst_gl_display_x11_new_with_display (display);
736   }
737 #endif
738   else if (g_strcmp0 (context_type, "gst.gl.app_context") == 0) {
739     const GstStructure *s = gst_context_get_structure (context);
740     GstGLDisplay *context_display;
741     GstGLDisplay *element_display;
742
743     if (gst_structure_get (s, "context", GST_GL_TYPE_CONTEXT,
744             &context_replacement, NULL)) {
745       context_display = gst_gl_context_get_display (context_replacement);
746       element_display = display_replacement ? display_replacement : *display;
747       if (element_display
748           && (gst_gl_display_get_handle_type (element_display) &
749               gst_gl_display_get_handle_type (context_display)) == 0) {
750         GST_ELEMENT_WARNING (element, LIBRARY, SETTINGS, ("%s",
751                 "Cannot set a GL context with a different display type"), ("%s",
752                 "Cannot set a GL context with a different display type"));
753         gst_object_unref (context_replacement);
754         context_replacement = NULL;
755       }
756       gst_object_unref (context_display);
757     }
758   }
759
760   if (display_replacement) {
761     GstGLDisplay *old = *display;
762     *display = display_replacement;
763
764     if (old)
765       gst_object_unref (old);
766   }
767
768   if (context_replacement) {
769     GstGLContext *old = *other_context;
770     *other_context = context_replacement;
771
772     if (old)
773       gst_object_unref (old);
774   }
775
776   return TRUE;
777 }
778
779 gboolean
780 gst_gl_handle_context_query (GstElement * element, GstQuery * query,
781     GstGLDisplay ** display, GstGLContext ** other_context)
782 {
783   gboolean res = FALSE;
784   const gchar *context_type;
785   GstContext *context, *old_context;
786
787   g_return_val_if_fail (element != NULL, FALSE);
788   g_return_val_if_fail (query != NULL, FALSE);
789   g_return_val_if_fail (display != NULL, FALSE);
790   g_return_val_if_fail (other_context != NULL, FALSE);
791
792   gst_query_parse_context_type (query, &context_type);
793
794   if (g_strcmp0 (context_type, GST_GL_DISPLAY_CONTEXT_TYPE) == 0) {
795
796     gst_query_parse_context (query, &old_context);
797
798     if (old_context)
799       context = gst_context_copy (old_context);
800     else
801       context = gst_context_new (GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
802
803     gst_context_set_gl_display (context, *display);
804     gst_query_set_context (query, context);
805     gst_context_unref (context);
806
807     res = *display != NULL;
808   }
809 #if GST_GL_HAVE_WINDOW_X11
810   else if (g_strcmp0 (context_type, "gst.x11.display.handle") == 0) {
811     GstStructure *s;
812     Display *x11_display = NULL;
813
814     gst_query_parse_context (query, &old_context);
815
816     if (old_context)
817       context = gst_context_copy (old_context);
818     else
819       context = gst_context_new ("gst.x11.display.handle", TRUE);
820
821     if (*display
822         && ((*display)->type & GST_GL_DISPLAY_TYPE_X11) ==
823         GST_GL_DISPLAY_TYPE_X11)
824       x11_display = (Display *) gst_gl_display_get_handle (*display);
825
826     s = gst_context_writable_structure (context);
827     gst_structure_set (s, "display", G_TYPE_POINTER, x11_display, NULL);
828
829     gst_query_set_context (query, context);
830     gst_context_unref (context);
831
832     res = x11_display != NULL;
833   }
834 #endif
835   else if (g_strcmp0 (context_type, "gst.gl.app_context") == 0) {
836     GstStructure *s;
837
838     gst_query_parse_context (query, &old_context);
839
840     if (old_context)
841       context = gst_context_copy (old_context);
842     else
843       context = gst_context_new ("gst.gl.app_context", TRUE);
844
845     s = gst_context_writable_structure (context);
846     gst_structure_set (s, "context", GST_GL_TYPE_CONTEXT, *other_context, NULL);
847     gst_query_set_context (query, context);
848     gst_context_unref (context);
849
850     res = *other_context != NULL;
851   }
852
853   return res;
854 }
855
856 gsize
857 gst_gl_get_plane_data_size (GstVideoInfo * info, GstVideoAlignment * align,
858     guint plane)
859 {
860   gint padded_height;
861   gsize plane_size;
862
863   padded_height = info->height;
864
865   if (align)
866     padded_height += align->padding_top + align->padding_bottom;
867
868   padded_height =
869       GST_VIDEO_FORMAT_INFO_SCALE_HEIGHT (info->finfo, plane, padded_height);
870
871   plane_size = GST_VIDEO_INFO_PLANE_STRIDE (info, plane) * padded_height;
872
873   return plane_size;
874 }
875
876 GstCaps *
877 gst_gl_caps_replace_all_caps_features (const GstCaps * caps,
878     const gchar * feature_name)
879 {
880   GstCaps *tmp = gst_caps_copy (caps);
881   guint n = gst_caps_get_size (tmp);
882   guint i = 0;
883
884   for (i = 0; i < n; i++) {
885     GstCapsFeatures *features = gst_caps_get_features (tmp, i);
886     if (features) {
887       guint n_f = gst_caps_features_get_size (features);
888       guint j = 0;
889       for (j = 0; j < n_f; j++) {
890         gst_caps_features_remove_id (features,
891             gst_caps_features_get_nth_id (features, j));
892       }
893     }
894
895     gst_caps_features_add (features, feature_name);
896   }
897
898   return tmp;
899 }