• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4  * Copyright (C) 2002,2007 David A. Schleef <ds@schleef.org>
5  * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
6  * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
7  * Copyright (C) 2019 Philippe Normand <philn@igalia.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <gst/gl/gl.h>
30 #include <gst/gst-i18n-plugin.h>
31 
32 /**
33  * SECTION:gstglbasesrc
34  * @short_description: #GstPushSrc subclass for injecting OpenGL resources in a pipeline
35  * @title: GstGLBaseSrc
36  * @see_also: #GstPushSrc
37  *
38  * #GstGLBaseSrc handles the nitty gritty details of retrieving an OpenGL
39  * context. It also provided some wrappers around #GstBaseSrc's `start()` and
40  * `stop()` virtual methods that ensure an OpenGL context is available and
41  * current in the calling thread.
42  *
43  * Since: 1.18
44  */
45 
46 #define GST_CAT_DEFAULT gst_gl_base_src_debug
47 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
48 
49 struct _GstGLBaseSrcPrivate
50 {
51   GstGLContext *other_context;
52 
53   GstGLMemory *out_tex;
54   gint64 timestamp_offset;      /* base offset */
55   gint64 n_frames;              /* total frames sent */
56   gboolean negotiated;
57   gboolean gl_result;
58   gboolean gl_started;
59 
60   GRecMutex context_lock;
61 };
62 
63 /* Properties */
64 enum
65 {
66   PROP_0,
67   PROP_TIMESTAMP_OFFSET
68 };
69 
70 #define gst_gl_base_src_parent_class parent_class
71 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstGLBaseSrc, gst_gl_base_src,
72     GST_TYPE_PUSH_SRC, G_ADD_PRIVATE (GstGLBaseSrc)
73     GST_DEBUG_CATEGORY_INIT (gst_gl_base_src_debug,
74         "glbasesrc", 0, "glbasesrc element");
75     );
76 
77 static void gst_gl_base_src_finalize (GObject * object);
78 static void gst_gl_base_src_set_property (GObject * object, guint prop_id,
79     const GValue * value, GParamSpec * pspec);
80 static void gst_gl_base_src_get_property (GObject * object, guint prop_id,
81     GValue * value, GParamSpec * pspec);
82 
83 static gboolean gst_gl_base_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
84 static gboolean gst_gl_base_src_query (GstBaseSrc * bsrc, GstQuery * query);
85 static void gst_gl_base_src_set_context (GstElement * element,
86     GstContext * context);
87 static GstStateChangeReturn gst_gl_base_src_change_state (GstElement * element,
88     GstStateChange transition);
89 
90 static void gst_gl_base_src_get_times (GstBaseSrc * basesrc,
91     GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
92 static GstFlowReturn gst_gl_base_src_fill (GstPushSrc * psrc,
93     GstBuffer * buffer);
94 static gboolean gst_gl_base_src_start (GstBaseSrc * basesrc);
95 static gboolean gst_gl_base_src_stop (GstBaseSrc * basesrc);
96 static gboolean gst_gl_base_src_decide_allocation (GstBaseSrc * basesrc,
97     GstQuery * query);
98 static gboolean gst_gl_base_src_do_seek (GstBaseSrc * basesrc,
99     GstSegment * segment);
100 
101 static gboolean gst_gl_base_src_default_gl_start (GstGLBaseSrc * src);
102 static void gst_gl_base_src_default_gl_stop (GstGLBaseSrc * src);
103 static gboolean gst_gl_base_src_default_fill_gl_memory (GstGLBaseSrc * src,
104     GstGLMemory * mem);
105 
106 static gboolean gst_gl_base_src_find_gl_context_unlocked (GstGLBaseSrc * src);
107 
108 static void
gst_gl_base_src_class_init(GstGLBaseSrcClass * klass)109 gst_gl_base_src_class_init (GstGLBaseSrcClass * klass)
110 {
111   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
112   GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
113   GstPushSrcClass *gstpushsrc_class = GST_PUSH_SRC_CLASS (klass);
114   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
115 
116   gobject_class->finalize = gst_gl_base_src_finalize;
117   gobject_class->set_property = gst_gl_base_src_set_property;
118   gobject_class->get_property = gst_gl_base_src_get_property;
119 
120   g_object_class_install_property (gobject_class,
121       PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset",
122           "Timestamp offset",
123           "An offset added to timestamps set on buffers (in ns)", G_MININT64,
124           G_MAXINT64, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
125 
126   element_class->set_context = GST_DEBUG_FUNCPTR (gst_gl_base_src_set_context);
127   element_class->change_state =
128       GST_DEBUG_FUNCPTR (gst_gl_base_src_change_state);
129 
130   gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_gl_base_src_setcaps);
131   gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_gl_base_src_query);
132   gstbasesrc_class->get_times = GST_DEBUG_FUNCPTR (gst_gl_base_src_get_times);
133   gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_gl_base_src_start);
134   gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_gl_base_src_stop);
135   gstbasesrc_class->decide_allocation =
136       GST_DEBUG_FUNCPTR (gst_gl_base_src_decide_allocation);
137   gstbasesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_gl_base_src_do_seek);
138 
139   gstpushsrc_class->fill = GST_DEBUG_FUNCPTR (gst_gl_base_src_fill);
140 
141   klass->supported_gl_api = GST_GL_API_ANY;
142   klass->gl_start = GST_DEBUG_FUNCPTR (gst_gl_base_src_default_gl_start);
143   klass->gl_stop = GST_DEBUG_FUNCPTR (gst_gl_base_src_default_gl_stop);
144   klass->fill_gl_memory =
145       GST_DEBUG_FUNCPTR (gst_gl_base_src_default_fill_gl_memory);
146 }
147 
148 static void
gst_gl_base_src_init(GstGLBaseSrc * src)149 gst_gl_base_src_init (GstGLBaseSrc * src)
150 {
151   src->priv = gst_gl_base_src_get_instance_private (src);
152   src->priv->timestamp_offset = 0;
153   g_rec_mutex_init (&src->priv->context_lock);
154 
155   /* we operate in time */
156   gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
157   gst_base_src_set_live (GST_BASE_SRC (src), FALSE);
158 }
159 
160 static void
gst_gl_base_src_finalize(GObject * object)161 gst_gl_base_src_finalize (GObject * object)
162 {
163   GstGLBaseSrc *src = GST_GL_BASE_SRC (object);
164 
165   g_rec_mutex_clear (&src->priv->context_lock);
166 
167   G_OBJECT_CLASS (parent_class)->finalize (object);
168 }
169 
170 static void
gst_gl_base_src_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)171 gst_gl_base_src_set_property (GObject * object, guint prop_id,
172     const GValue * value, GParamSpec * pspec)
173 {
174   GstGLBaseSrc *src = GST_GL_BASE_SRC (object);
175 
176   switch (prop_id) {
177     case PROP_TIMESTAMP_OFFSET:
178       src->priv->timestamp_offset = g_value_get_int64 (value);
179       break;
180     default:
181       break;
182   }
183 }
184 
185 static void
gst_gl_base_src_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)186 gst_gl_base_src_get_property (GObject * object, guint prop_id,
187     GValue * value, GParamSpec * pspec)
188 {
189   GstGLBaseSrc *src = GST_GL_BASE_SRC (object);
190 
191   switch (prop_id) {
192     case PROP_TIMESTAMP_OFFSET:
193       g_value_set_int64 (value, src->priv->timestamp_offset);
194       break;
195     default:
196       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
197       break;
198   }
199 }
200 
201 static gboolean
gst_gl_base_src_setcaps(GstBaseSrc * bsrc,GstCaps * caps)202 gst_gl_base_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
203 {
204   GstGLBaseSrc *glbasesrc = GST_GL_BASE_SRC (bsrc);
205 
206   GST_DEBUG_OBJECT (bsrc, "set caps %" GST_PTR_FORMAT, caps);
207 
208   if (!gst_video_info_from_caps (&glbasesrc->out_info, caps))
209     goto wrong_caps;
210 
211   glbasesrc->priv->negotiated = TRUE;
212 
213   gst_caps_replace (&glbasesrc->out_caps, caps);
214 
215   return TRUE;
216 
217 /* ERRORS */
218 wrong_caps:
219   {
220     GST_WARNING_OBJECT (bsrc, "wrong caps");
221     return FALSE;
222   }
223 }
224 
225 static void
gst_gl_base_src_set_context(GstElement * element,GstContext * context)226 gst_gl_base_src_set_context (GstElement * element, GstContext * context)
227 {
228   GstGLBaseSrc *src = GST_GL_BASE_SRC (element);
229   GstGLBaseSrcClass *klass = GST_GL_BASE_SRC_GET_CLASS (src);
230   GstGLDisplay *old_display, *new_display;
231 
232   g_rec_mutex_lock (&src->priv->context_lock);
233   old_display = src->display ? gst_object_ref (src->display) : NULL;
234   gst_gl_handle_set_context (element, context, &src->display,
235       &src->priv->other_context);
236   if (src->display)
237     gst_gl_display_filter_gl_api (src->display, klass->supported_gl_api);
238   new_display = src->display ? gst_object_ref (src->display) : NULL;
239 
240   if (old_display && new_display) {
241     if (old_display != new_display) {
242       gst_clear_object (&src->context);
243       if (gst_gl_base_src_find_gl_context_unlocked (src)) {
244         gst_pad_mark_reconfigure (GST_BASE_SRC_PAD (src));
245       }
246     }
247   }
248   gst_clear_object (&old_display);
249   gst_clear_object (&new_display);
250   g_rec_mutex_unlock (&src->priv->context_lock);
251 
252   GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
253 }
254 
255 static gboolean
gst_gl_base_src_query(GstBaseSrc * bsrc,GstQuery * query)256 gst_gl_base_src_query (GstBaseSrc * bsrc, GstQuery * query)
257 {
258   gboolean res = FALSE;
259   GstGLBaseSrc *src;
260 
261   src = GST_GL_BASE_SRC (bsrc);
262 
263   switch (GST_QUERY_TYPE (query)) {
264     case GST_QUERY_CONTEXT:
265     {
266       GstGLDisplay *display = NULL;
267       GstGLContext *other = NULL, *local = NULL;
268       gboolean ret;
269 
270       g_rec_mutex_lock (&src->priv->context_lock);
271       if (src->display)
272         display = gst_object_ref (src->display);
273       if (src->context)
274         local = gst_object_ref (src->context);
275       if (src->priv->other_context)
276         other = gst_object_ref (src->priv->other_context);
277       g_rec_mutex_unlock (&src->priv->context_lock);
278 
279       ret = gst_gl_handle_context_query ((GstElement *) src, query,
280           display, local, other);
281 
282       gst_clear_object (&display);
283       gst_clear_object (&other);
284       gst_clear_object (&local);
285 
286       if (ret)
287         return ret;
288       break;
289     }
290     case GST_QUERY_CONVERT:
291     {
292       GstFormat src_fmt, dest_fmt;
293       gint64 src_val, dest_val;
294 
295       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
296       res =
297           gst_video_info_convert (&src->out_info, src_fmt, src_val, dest_fmt,
298           &dest_val);
299       gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
300 
301       return res;
302     }
303     default:
304       break;
305   }
306 
307   return GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
308 }
309 
310 static void
gst_gl_base_src_get_times(GstBaseSrc * basesrc,GstBuffer * buffer,GstClockTime * start,GstClockTime * end)311 gst_gl_base_src_get_times (GstBaseSrc * basesrc, GstBuffer * buffer,
312     GstClockTime * start, GstClockTime * end)
313 {
314   /* for live sources, sync on the timestamp of the buffer */
315   if (gst_base_src_is_live (basesrc)) {
316     GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
317 
318     if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
319       /* get duration to calculate end time */
320       GstClockTime duration = GST_BUFFER_DURATION (buffer);
321 
322       if (GST_CLOCK_TIME_IS_VALID (duration))
323         *end = timestamp + duration;
324       *start = timestamp;
325     }
326   } else {
327     *start = -1;
328     *end = -1;
329   }
330 }
331 
332 static gboolean
gst_gl_base_src_default_gl_start(GstGLBaseSrc * src)333 gst_gl_base_src_default_gl_start (GstGLBaseSrc * src)
334 {
335   return TRUE;
336 }
337 
338 static void
gst_gl_base_src_gl_start(GstGLContext * context,gpointer data)339 gst_gl_base_src_gl_start (GstGLContext * context, gpointer data)
340 {
341   GstGLBaseSrc *src = GST_GL_BASE_SRC (data);
342   GstGLBaseSrcClass *src_class = GST_GL_BASE_SRC_GET_CLASS (src);
343 
344   GST_INFO_OBJECT (src, "starting");
345   gst_gl_insert_debug_marker (src->context,
346       "starting element %s", GST_OBJECT_NAME (src));
347 
348   src->priv->gl_started = src_class->gl_start (src);
349 }
350 
351 static void
gst_gl_base_src_default_gl_stop(GstGLBaseSrc * src)352 gst_gl_base_src_default_gl_stop (GstGLBaseSrc * src)
353 {
354 }
355 
356 static void
gst_gl_base_src_gl_stop(GstGLContext * context,gpointer data)357 gst_gl_base_src_gl_stop (GstGLContext * context, gpointer data)
358 {
359   GstGLBaseSrc *src = GST_GL_BASE_SRC (data);
360   GstGLBaseSrcClass *src_class = GST_GL_BASE_SRC_GET_CLASS (src);
361 
362   GST_INFO_OBJECT (src, "stopping");
363   gst_gl_insert_debug_marker (src->context,
364       "stopping element %s", GST_OBJECT_NAME (src));
365 
366   src->priv->out_tex = NULL;
367 
368   if (src->priv->gl_started)
369     src_class->gl_stop (src);
370 
371   src->priv->gl_started = FALSE;
372 }
373 
374 static gboolean
gst_gl_base_src_default_fill_gl_memory(GstGLBaseSrc * src,GstGLMemory * mem)375 gst_gl_base_src_default_fill_gl_memory (GstGLBaseSrc * src, GstGLMemory * mem)
376 {
377   return TRUE;
378 }
379 
380 static void
_fill_gl(GstGLContext * context,GstGLBaseSrc * src)381 _fill_gl (GstGLContext * context, GstGLBaseSrc * src)
382 {
383   GstGLBaseSrcClass *klass = GST_GL_BASE_SRC_GET_CLASS (src);
384 
385   GST_TRACE_OBJECT (src, "filling gl memory %p", src->priv->out_tex);
386   src->priv->gl_result = klass->fill_gl_memory (src, src->priv->out_tex);
387 }
388 
389 static GstFlowReturn
gst_gl_base_src_fill(GstPushSrc * psrc,GstBuffer * buffer)390 gst_gl_base_src_fill (GstPushSrc * psrc, GstBuffer * buffer)
391 {
392   GstGLBaseSrc *src = GST_GL_BASE_SRC (psrc);
393   GstClockTime next_time;
394   GstVideoFrame out_frame;
395   GstGLSyncMeta *sync_meta;
396 
397   g_rec_mutex_lock (&src->priv->context_lock);
398   if (G_UNLIKELY (!src->priv->negotiated || !src->context))
399     goto not_negotiated;
400 
401   /* 0 framerate and we are at the second frame, eos */
402   if (G_UNLIKELY (GST_VIDEO_INFO_FPS_N (&src->out_info) == 0
403           && src->priv->n_frames == 1))
404     goto eos;
405 
406   if (!gst_video_frame_map (&out_frame, &src->out_info, buffer,
407           GST_MAP_WRITE | GST_MAP_GL)) {
408     return GST_FLOW_NOT_NEGOTIATED;
409   }
410 
411   src->priv->out_tex = (GstGLMemory *) out_frame.map[0].memory;
412 
413   gst_gl_context_thread_add (src->context, (GstGLContextThreadFunc) _fill_gl,
414       src);
415   gst_video_frame_unmap (&out_frame);
416   if (!src->priv->gl_result)
417     goto gl_error;
418 
419   sync_meta = gst_buffer_get_gl_sync_meta (buffer);
420   if (sync_meta)
421     gst_gl_sync_meta_set_sync_point (sync_meta, src->context);
422   g_rec_mutex_unlock (&src->priv->context_lock);
423 
424   GST_BUFFER_TIMESTAMP (buffer) =
425       src->priv->timestamp_offset + src->running_time;
426   GST_BUFFER_OFFSET (buffer) = src->priv->n_frames;
427   src->priv->n_frames++;
428   GST_BUFFER_OFFSET_END (buffer) = src->priv->n_frames;
429   if (src->out_info.fps_n) {
430     next_time = gst_util_uint64_scale_int (src->priv->n_frames * GST_SECOND,
431         src->out_info.fps_d, src->out_info.fps_n);
432     GST_BUFFER_DURATION (buffer) = next_time - src->running_time;
433   } else {
434     next_time = src->priv->timestamp_offset;
435     /* NONE means forever */
436     GST_BUFFER_DURATION (buffer) = GST_CLOCK_TIME_NONE;
437   }
438 
439   src->running_time = next_time;
440 
441   return GST_FLOW_OK;
442 
443 gl_error:
444   {
445     g_rec_mutex_unlock (&src->priv->context_lock);
446     GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (_("failed to draw pattern")),
447         (_("A GL error occurred")));
448     return GST_FLOW_NOT_NEGOTIATED;
449   }
450 not_negotiated:
451   {
452     g_rec_mutex_unlock (&src->priv->context_lock);
453     GST_ELEMENT_ERROR (src, CORE, NEGOTIATION, (NULL),
454         (_("format wasn't negotiated before get function")));
455     return GST_FLOW_NOT_NEGOTIATED;
456   }
457 eos:
458   {
459     g_rec_mutex_unlock (&src->priv->context_lock);
460     GST_DEBUG_OBJECT (src, "eos: 0 framerate, frame %d",
461         (gint) src->priv->n_frames);
462     return GST_FLOW_EOS;
463   }
464 }
465 
466 static gboolean
gst_gl_base_src_start(GstBaseSrc * basesrc)467 gst_gl_base_src_start (GstBaseSrc * basesrc)
468 {
469   GstGLBaseSrc *src = GST_GL_BASE_SRC (basesrc);
470 
471   src->running_time = 0;
472   src->priv->n_frames = 0;
473   src->priv->negotiated = FALSE;
474 
475   return TRUE;
476 }
477 
478 static gboolean
gst_gl_base_src_stop(GstBaseSrc * basesrc)479 gst_gl_base_src_stop (GstBaseSrc * basesrc)
480 {
481   GstGLBaseSrc *src = GST_GL_BASE_SRC (basesrc);
482 
483   g_rec_mutex_lock (&src->priv->context_lock);
484   gst_caps_replace (&src->out_caps, NULL);
485 
486   if (src->context) {
487     if (src->priv->gl_started)
488       gst_gl_context_thread_add (src->context, gst_gl_base_src_gl_stop, src);
489 
490     gst_object_unref (src->context);
491   }
492   src->context = NULL;
493   g_rec_mutex_unlock (&src->priv->context_lock);
494 
495   return TRUE;
496 }
497 
498 static gboolean
_find_local_gl_context_unlocked(GstGLBaseSrc * src)499 _find_local_gl_context_unlocked (GstGLBaseSrc * src)
500 {
501   GstGLContext *context, *prev_context;
502   gboolean ret;
503 
504   if (src->context && src->context->display == src->display)
505     return TRUE;
506 
507   context = prev_context = src->context;
508   g_rec_mutex_unlock (&src->priv->context_lock);
509   /* we need to drop the lock to query as another element may also be
510    * performing a context query on us which would also attempt to take the
511    * context_lock. Our query could block on the same lock in the other element.
512    */
513   ret =
514       gst_gl_query_local_gl_context (GST_ELEMENT (src), GST_PAD_SRC, &context);
515   g_rec_mutex_lock (&src->priv->context_lock);
516   if (ret) {
517     if (src->context != prev_context) {
518       /* we need to recheck everything since we dropped the lock and the
519        * context has changed */
520       if (src->context && src->context->display == src->display) {
521         if (context != src->context)
522           gst_clear_object (&context);
523         return TRUE;
524       }
525     }
526 
527     if (context->display == src->display) {
528       src->context = context;
529       return TRUE;
530     }
531     if (context != src->context)
532       gst_clear_object (&context);
533   }
534   return FALSE;
535 }
536 
537 static gboolean
gst_gl_base_src_find_gl_context_unlocked(GstGLBaseSrc * src)538 gst_gl_base_src_find_gl_context_unlocked (GstGLBaseSrc * src)
539 {
540   GstGLBaseSrcClass *klass = GST_GL_BASE_SRC_GET_CLASS (src);
541   GError *error = NULL;
542   gboolean new_context = FALSE;
543 
544   GST_DEBUG_OBJECT (src, "attempting to find an OpenGL context, existing %"
545       GST_PTR_FORMAT, src->context);
546 
547   if (!src->context)
548     new_context = TRUE;
549 
550   if (!gst_gl_ensure_element_data (src, &src->display,
551           &src->priv->other_context))
552     return FALSE;
553 
554   gst_gl_display_filter_gl_api (src->display, klass->supported_gl_api);
555 
556   _find_local_gl_context_unlocked (src);
557 
558   if (!src->context) {
559     GST_OBJECT_LOCK (src->display);
560     do {
561       if (src->context) {
562         gst_object_unref (src->context);
563         src->context = NULL;
564       }
565       /* just get a GL context.  we don't care */
566       src->context =
567           gst_gl_display_get_gl_context_for_thread (src->display, NULL);
568       if (!src->context) {
569         if (!gst_gl_display_create_context (src->display,
570                 src->priv->other_context, &src->context, &error)) {
571           GST_OBJECT_UNLOCK (src->display);
572           goto context_error;
573         }
574       }
575     } while (!gst_gl_display_add_context (src->display, src->context));
576     GST_OBJECT_UNLOCK (src->display);
577   }
578   GST_INFO_OBJECT (src, "found OpenGL context %" GST_PTR_FORMAT, src->context);
579 
580   if (new_context || !src->priv->gl_started) {
581     if (src->priv->gl_started)
582       gst_gl_context_thread_add (src->context, gst_gl_base_src_gl_stop, src);
583 
584     {
585       if ((gst_gl_context_get_gl_api (src->
586                   context) & klass->supported_gl_api) == 0)
587         goto unsupported_gl_api;
588     }
589 
590     gst_gl_context_thread_add (src->context, gst_gl_base_src_gl_start, src);
591 
592     if (!src->priv->gl_started)
593       goto error;
594   }
595 
596   return TRUE;
597 
598 unsupported_gl_api:
599   {
600     GstGLAPI gl_api = gst_gl_context_get_gl_api (src->context);
601     gchar *gl_api_str = gst_gl_api_to_string (gl_api);
602     gchar *supported_gl_api_str =
603         gst_gl_api_to_string (klass->supported_gl_api);
604     GST_ELEMENT_ERROR (src, RESOURCE, BUSY,
605         ("GL API's not compatible context: %s supported: %s", gl_api_str,
606             supported_gl_api_str), (NULL));
607 
608     g_free (supported_gl_api_str);
609     g_free (gl_api_str);
610     return FALSE;
611   }
612 context_error:
613   {
614     if (error) {
615       GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s", error->message),
616           (NULL));
617       g_clear_error (&error);
618     } else {
619       GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), (NULL));
620     }
621     if (src->context)
622       gst_object_unref (src->context);
623     src->context = NULL;
624     return FALSE;
625   }
626 error:
627   {
628     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
629         ("Subclass failed to initialize."), (NULL));
630     return FALSE;
631   }
632 }
633 
634 static gboolean
gst_gl_base_src_decide_allocation(GstBaseSrc * basesrc,GstQuery * query)635 gst_gl_base_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query)
636 {
637   GstGLBaseSrc *src = GST_GL_BASE_SRC (basesrc);
638   GstGLContext *context;
639   GstBufferPool *pool = NULL;
640   GstStructure *config;
641   GstCaps *caps;
642   guint min, max, size;
643   gboolean update_pool;
644 
645   g_rec_mutex_lock (&src->priv->context_lock);
646   if (!gst_gl_base_src_find_gl_context_unlocked (src)) {
647     g_rec_mutex_unlock (&src->priv->context_lock);
648     return FALSE;
649   }
650   context = gst_object_ref (src->context);
651   g_rec_mutex_unlock (&src->priv->context_lock);
652 
653   gst_query_parse_allocation (query, &caps, NULL);
654 
655   if (gst_query_get_n_allocation_pools (query) > 0) {
656     gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
657 
658     update_pool = TRUE;
659   } else {
660     GstVideoInfo vinfo;
661 
662     gst_video_info_init (&vinfo);
663     gst_video_info_from_caps (&vinfo, caps);
664     size = vinfo.size;
665     min = max = 0;
666     update_pool = FALSE;
667   }
668 
669   if (!pool || !GST_IS_GL_BUFFER_POOL (pool)) {
670     /* can't use this pool */
671     if (pool)
672       gst_object_unref (pool);
673     pool = gst_gl_buffer_pool_new (context);
674   }
675   config = gst_buffer_pool_get_config (pool);
676 
677   gst_buffer_pool_config_set_params (config, caps, size, min, max);
678   gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META);
679   if (gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL))
680     gst_buffer_pool_config_add_option (config,
681         GST_BUFFER_POOL_OPTION_GL_SYNC_META);
682   gst_buffer_pool_config_add_option (config,
683       GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
684 
685   gst_buffer_pool_set_config (pool, config);
686 
687   if (update_pool)
688     gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
689   else
690     gst_query_add_allocation_pool (query, pool, size, min, max);
691 
692   gst_object_unref (pool);
693   gst_object_unref (context);
694 
695   return TRUE;
696 }
697 
698 static GstStateChangeReturn
gst_gl_base_src_change_state(GstElement * element,GstStateChange transition)699 gst_gl_base_src_change_state (GstElement * element, GstStateChange transition)
700 {
701   GstGLBaseSrc *src = GST_GL_BASE_SRC (element);
702   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
703 
704   GST_DEBUG_OBJECT (src, "changing state: %s => %s",
705       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
706       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
707 
708   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
709   if (ret == GST_STATE_CHANGE_FAILURE)
710     return ret;
711 
712   switch (transition) {
713     case GST_STATE_CHANGE_READY_TO_NULL:
714       g_rec_mutex_lock (&src->priv->context_lock);
715       gst_clear_object (&src->priv->other_context);
716       gst_clear_object (&src->display);
717       g_rec_mutex_unlock (&src->priv->context_lock);
718       break;
719     default:
720       break;
721   }
722 
723   return ret;
724 }
725 
726 static gboolean
gst_gl_base_src_do_seek(GstBaseSrc * basesrc,GstSegment * segment)727 gst_gl_base_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment)
728 {
729   GstGLBaseSrc *src = GST_GL_BASE_SRC (basesrc);
730   GstClockTime time;
731   segment->time = segment->start;
732   time = segment->position;
733 
734   /* now move to the time indicated */
735   if (src->out_info.fps_n) {
736     src->priv->n_frames = gst_util_uint64_scale (time,
737         src->out_info.fps_n, src->out_info.fps_d * GST_SECOND);
738   } else
739     src->priv->n_frames = 0;
740 
741   if (src->out_info.fps_n) {
742     src->running_time = gst_util_uint64_scale (src->priv->n_frames,
743         src->out_info.fps_d * GST_SECOND, src->out_info.fps_n);
744   } else {
745     /* FIXME : Not sure what to set here */
746     src->running_time = 0;
747   }
748 
749   g_return_val_if_fail (src->running_time <= time, FALSE);
750 
751   return GST_BASE_SRC_CLASS (parent_class)->do_seek (basesrc, segment);
752 }
753