1 /*
2 * GStreamer
3 * Copyright (C) 2015 Matthew Waters <matthew@centricular.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
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/video/gstvideometa.h>
26
27 #include <gst/gl/gl.h>
28 #include <gst/gl/gstglutils_private.h>
29
30 /**
31 * SECTION:gstglbasefilter
32 * @short_description: #GstBaseTransform subclass for transforming OpenGL resources
33 * @title: GstGLBaseFilter
34 * @see_also: #GstBaseTransform
35 *
36 * #GstGLBaseFilter handles the nitty gritty details of retrieving an OpenGL
37 * context. It also provided some wrappers around #GstBaseTransform's
38 * `start()`, `stop()` and `set_caps()` virtual methods that ensure an OpenGL
39 * context is available and current in the calling thread.
40 */
41
42 #define GST_CAT_DEFAULT gst_gl_base_filter_debug
43 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
44
45 struct _GstGLBaseFilterPrivate
46 {
47 GstGLContext *other_context;
48
49 gboolean gl_result;
50 gboolean gl_started;
51
52 GRecMutex context_lock;
53 gboolean new_gl_context;
54 };
55
56 /* Properties */
57 enum
58 {
59 PROP_0,
60 PROP_CONTEXT
61 };
62
63 #define gst_gl_base_filter_parent_class parent_class
64 G_DEFINE_TYPE_WITH_CODE (GstGLBaseFilter, gst_gl_base_filter,
65 GST_TYPE_BASE_TRANSFORM, G_ADD_PRIVATE (GstGLBaseFilter)
66 GST_DEBUG_CATEGORY_INIT (gst_gl_base_filter_debug,
67 "glbasefilter", 0, "glbasefilter element");
68 );
69
70 static void gst_gl_base_filter_finalize (GObject * object);
71 static void gst_gl_base_filter_set_property (GObject * object, guint prop_id,
72 const GValue * value, GParamSpec * pspec);
73 static void gst_gl_base_filter_get_property (GObject * object, guint prop_id,
74 GValue * value, GParamSpec * pspec);
75
76 static void gst_gl_base_filter_set_context (GstElement * element,
77 GstContext * context);
78 static GstStateChangeReturn gst_gl_base_filter_change_state (GstElement *
79 element, GstStateChange transition);
80 static gboolean gst_gl_base_filter_query (GstBaseTransform * trans,
81 GstPadDirection direction, GstQuery * query);
82 static void gst_gl_base_filter_reset (GstGLBaseFilter * filter);
83 static gboolean gst_gl_base_filter_start (GstBaseTransform * bt);
84 static gboolean gst_gl_base_filter_stop (GstBaseTransform * bt);
85 static gboolean gst_gl_base_filter_set_caps (GstBaseTransform * bt,
86 GstCaps * incaps, GstCaps * outcaps);
87 static gboolean gst_gl_base_filter_decide_allocation (GstBaseTransform * trans,
88 GstQuery * query);
89
90 /* GstGLContextThreadFunc */
91 static void gst_gl_base_filter_gl_start (GstGLContext * context, gpointer data);
92 static void gst_gl_base_filter_gl_stop (GstGLContext * context, gpointer data);
93
94 static gboolean gst_gl_base_filter_default_gl_start (GstGLBaseFilter * filter);
95 static void gst_gl_base_filter_default_gl_stop (GstGLBaseFilter * filter);
96
97 static gboolean gst_gl_base_filter_find_gl_context_unlocked (GstGLBaseFilter *
98 filter);
99 static void
gst_gl_base_filter_class_init(GstGLBaseFilterClass * klass)100 gst_gl_base_filter_class_init (GstGLBaseFilterClass * klass)
101 {
102 GObjectClass *gobject_class;
103 GstElementClass *element_class;
104
105 gobject_class = (GObjectClass *) klass;
106 element_class = GST_ELEMENT_CLASS (klass);
107
108 gobject_class->finalize = gst_gl_base_filter_finalize;
109 gobject_class->set_property = gst_gl_base_filter_set_property;
110 gobject_class->get_property = gst_gl_base_filter_get_property;
111
112 GST_BASE_TRANSFORM_CLASS (klass)->query = gst_gl_base_filter_query;
113 GST_BASE_TRANSFORM_CLASS (klass)->set_caps = gst_gl_base_filter_set_caps;
114 GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_base_filter_start;
115 GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_base_filter_stop;
116 GST_BASE_TRANSFORM_CLASS (klass)->decide_allocation =
117 gst_gl_base_filter_decide_allocation;
118
119 element_class->set_context = gst_gl_base_filter_set_context;
120 element_class->change_state = gst_gl_base_filter_change_state;
121
122 g_object_class_install_property (gobject_class, PROP_CONTEXT,
123 g_param_spec_object ("context",
124 "OpenGL context",
125 "Get OpenGL context",
126 GST_TYPE_GL_CONTEXT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
127
128 klass->supported_gl_api = GST_GL_API_ANY;
129 klass->gl_start = gst_gl_base_filter_default_gl_start;
130 klass->gl_stop = gst_gl_base_filter_default_gl_stop;
131 }
132
133 static void
gst_gl_base_filter_init(GstGLBaseFilter * filter)134 gst_gl_base_filter_init (GstGLBaseFilter * filter)
135 {
136 gst_base_transform_set_qos_enabled (GST_BASE_TRANSFORM (filter), TRUE);
137
138 filter->priv = gst_gl_base_filter_get_instance_private (filter);
139
140 g_rec_mutex_init (&filter->priv->context_lock);
141 }
142
143 static void
gst_gl_base_filter_finalize(GObject * object)144 gst_gl_base_filter_finalize (GObject * object)
145 {
146 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (object);
147
148 gst_caps_replace (&filter->in_caps, NULL);
149 gst_caps_replace (&filter->out_caps, NULL);
150
151 g_rec_mutex_clear (&filter->priv->context_lock);
152
153 G_OBJECT_CLASS (parent_class)->finalize (object);
154 }
155
156 static void
gst_gl_base_filter_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)157 gst_gl_base_filter_set_property (GObject * object, guint prop_id,
158 const GValue * value, GParamSpec * pspec)
159 {
160 switch (prop_id) {
161 default:
162 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
163 break;
164 }
165 }
166
167 static void
gst_gl_base_filter_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)168 gst_gl_base_filter_get_property (GObject * object, guint prop_id,
169 GValue * value, GParamSpec * pspec)
170 {
171 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (object);
172
173 switch (prop_id) {
174 case PROP_CONTEXT:
175 g_value_set_object (value, filter->context);
176 break;
177 default:
178 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
179 break;
180 }
181 }
182
183 static gboolean
_find_local_gl_context_unlocked(GstGLBaseFilter * filter)184 _find_local_gl_context_unlocked (GstGLBaseFilter * filter)
185 {
186 GstGLContext *context, *prev_context;
187 gboolean ret;
188
189 if (filter->context && filter->context->display == filter->display)
190 return TRUE;
191
192 context = prev_context = filter->context;
193 g_rec_mutex_unlock (&filter->priv->context_lock);
194 /* we need to drop the lock to query as another element may also be
195 * performing a context query on us which would also attempt to take the
196 * context_lock. Our query could block on the same lock in the other element.
197 */
198 ret =
199 gst_gl_query_local_gl_context (GST_ELEMENT (filter), GST_PAD_SRC,
200 &context);
201 g_rec_mutex_lock (&filter->priv->context_lock);
202 if (ret) {
203 if (filter->context != prev_context) {
204 /* we need to recheck everything since we dropped the lock and the
205 * context has changed */
206 if (filter->context && filter->context->display == filter->display) {
207 if (context != filter->context)
208 gst_clear_object (&context);
209 return TRUE;
210 }
211 }
212
213 if (context->display == filter->display) {
214 filter->context = context;
215 return TRUE;
216 }
217 if (context != filter->context)
218 gst_clear_object (&context);
219 }
220
221 context = prev_context = filter->context;
222 g_rec_mutex_unlock (&filter->priv->context_lock);
223 /* we need to drop the lock to query as another element may also be
224 * performing a context query on us which would also attempt to take the
225 * context_lock. Our query could block on the same lock in the other element.
226 */
227 ret =
228 gst_gl_query_local_gl_context (GST_ELEMENT (filter), GST_PAD_SINK,
229 &context);
230 g_rec_mutex_lock (&filter->priv->context_lock);
231 if (ret) {
232 if (filter->context != prev_context) {
233 /* we need to recheck everything now that we dropped the lock */
234 if (filter->context && filter->context->display == filter->display) {
235 if (context != filter->context)
236 gst_clear_object (&context);
237 return TRUE;
238 }
239 }
240
241 if (context->display == filter->display) {
242 filter->context = context;
243 return TRUE;
244 }
245 if (context != filter->context)
246 gst_clear_object (&context);
247 }
248
249 return FALSE;
250 }
251
252 static gboolean
_find_local_gl_context(GstGLBaseFilter * filter)253 _find_local_gl_context (GstGLBaseFilter * filter)
254 {
255 gboolean ret;
256 g_rec_mutex_lock (&filter->priv->context_lock);
257 ret = _find_local_gl_context_unlocked (filter);
258 g_rec_mutex_unlock (&filter->priv->context_lock);
259 return ret;
260 }
261
262 static gboolean
gst_gl_base_filter_query(GstBaseTransform * trans,GstPadDirection direction,GstQuery * query)263 gst_gl_base_filter_query (GstBaseTransform * trans, GstPadDirection direction,
264 GstQuery * query)
265 {
266 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (trans);
267
268 switch (GST_QUERY_TYPE (query)) {
269 case GST_QUERY_ALLOCATION:
270 {
271 if (direction == GST_PAD_SINK
272 && gst_base_transform_is_passthrough (trans)) {
273 _find_local_gl_context (filter);
274
275 return gst_pad_peer_query (GST_BASE_TRANSFORM_SRC_PAD (trans), query);
276 }
277 break;
278 }
279 case GST_QUERY_CONTEXT:
280 {
281 GstGLDisplay *display = NULL;
282 GstGLContext *other = NULL, *local = NULL;
283 gboolean ret;
284
285 g_rec_mutex_lock (&filter->priv->context_lock);
286 if (filter->display)
287 display = gst_object_ref (filter->display);
288 if (filter->context)
289 local = gst_object_ref (filter->context);
290 if (filter->priv->other_context)
291 other = gst_object_ref (filter->priv->other_context);
292 g_rec_mutex_unlock (&filter->priv->context_lock);
293
294 ret = gst_gl_handle_context_query ((GstElement *) filter, query,
295 display, local, other);
296
297 gst_clear_object (&display);
298 gst_clear_object (&other);
299 gst_clear_object (&local);
300
301 if (ret)
302 return TRUE;
303 break;
304 }
305 default:
306 break;
307 }
308
309 return GST_BASE_TRANSFORM_CLASS (parent_class)->query (trans, direction,
310 query);
311 }
312
313 static void
gst_gl_base_filter_reset(GstGLBaseFilter * filter)314 gst_gl_base_filter_reset (GstGLBaseFilter * filter)
315 {
316 g_rec_mutex_lock (&filter->priv->context_lock);
317 if (filter->context) {
318 gst_gl_context_thread_add (filter->context, gst_gl_base_filter_gl_stop,
319 filter);
320 gst_object_unref (filter->context);
321 filter->context = NULL;
322 }
323 g_rec_mutex_unlock (&filter->priv->context_lock);
324 }
325
326 static gboolean
gst_gl_base_filter_start(GstBaseTransform * bt)327 gst_gl_base_filter_start (GstBaseTransform * bt)
328 {
329 return TRUE;
330 }
331
332 static gboolean
gst_gl_base_filter_stop(GstBaseTransform * bt)333 gst_gl_base_filter_stop (GstBaseTransform * bt)
334 {
335 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (bt);
336
337 gst_gl_base_filter_reset (filter);
338
339 return TRUE;
340 }
341
342 static gboolean
gst_gl_base_filter_default_gl_start(GstGLBaseFilter * filter)343 gst_gl_base_filter_default_gl_start (GstGLBaseFilter * filter)
344 {
345 return TRUE;
346 }
347
348 static void
gst_gl_base_filter_gl_start(GstGLContext * context,gpointer data)349 gst_gl_base_filter_gl_start (GstGLContext * context, gpointer data)
350 {
351 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (data);
352 GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter);
353
354 GST_INFO_OBJECT (filter, "starting");
355 gst_gl_insert_debug_marker (filter->context,
356 "starting element %s", GST_OBJECT_NAME (filter));
357
358 filter->priv->gl_started = filter_class->gl_start (filter);
359 }
360
361 static void
gst_gl_base_filter_default_gl_stop(GstGLBaseFilter * filter)362 gst_gl_base_filter_default_gl_stop (GstGLBaseFilter * filter)
363 {
364 }
365
366 static void
gst_gl_base_filter_gl_stop(GstGLContext * context,gpointer data)367 gst_gl_base_filter_gl_stop (GstGLContext * context, gpointer data)
368 {
369 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (data);
370 GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter);
371
372 GST_INFO_OBJECT (filter, "stopping");
373 gst_gl_insert_debug_marker (filter->context,
374 "stopping element %s", GST_OBJECT_NAME (filter));
375
376 if (filter->priv->gl_started)
377 filter_class->gl_stop (filter);
378
379 filter->priv->gl_started = FALSE;
380 }
381
382 static void
_gl_set_caps(GstGLContext * context,GstGLBaseFilter * filter)383 _gl_set_caps (GstGLContext * context, GstGLBaseFilter * filter)
384 {
385 GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter);
386
387 GST_INFO_OBJECT (filter, "set GL caps input %" GST_PTR_FORMAT,
388 filter->in_caps);
389 GST_INFO_OBJECT (filter, "set GL caps output %" GST_PTR_FORMAT,
390 filter->out_caps);
391
392 if (filter_class->gl_set_caps)
393 filter->priv->gl_result =
394 filter_class->gl_set_caps (filter, filter->in_caps, filter->out_caps);
395 }
396
397 static gboolean
gl_set_caps_unlocked(GstGLBaseFilter * filter)398 gl_set_caps_unlocked (GstGLBaseFilter * filter)
399 {
400 GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter);
401
402 if (filter_class->gl_set_caps) {
403 gst_gl_context_thread_add (filter->context,
404 (GstGLContextThreadFunc) _gl_set_caps, filter);
405 return filter->priv->gl_result;
406 }
407
408 return TRUE;
409 }
410
411 static gboolean
gst_gl_base_filter_decide_allocation(GstBaseTransform * trans,GstQuery * query)412 gst_gl_base_filter_decide_allocation (GstBaseTransform * trans,
413 GstQuery * query)
414 {
415 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (trans);
416
417 g_rec_mutex_lock (&filter->priv->context_lock);
418 if (!gst_gl_base_filter_find_gl_context_unlocked (filter)) {
419 g_rec_mutex_unlock (&filter->priv->context_lock);
420 return FALSE;
421 }
422
423 if (!gl_set_caps_unlocked (filter))
424 goto error;
425
426 g_rec_mutex_unlock (&filter->priv->context_lock);
427
428 return GST_BASE_TRANSFORM_CLASS (parent_class)->decide_allocation (trans,
429 query);
430
431 error:
432 {
433 g_rec_mutex_unlock (&filter->priv->context_lock);
434 GST_ELEMENT_ERROR (trans, LIBRARY, INIT,
435 ("Subclass failed to initialize."), (NULL));
436 return FALSE;
437 }
438 }
439
440 static gboolean
gst_gl_base_filter_set_caps(GstBaseTransform * bt,GstCaps * incaps,GstCaps * outcaps)441 gst_gl_base_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps,
442 GstCaps * outcaps)
443 {
444 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (bt);
445
446 gst_caps_replace (&filter->in_caps, incaps);
447 gst_caps_replace (&filter->out_caps, outcaps);
448
449 return TRUE;
450 }
451
452 static GstStateChangeReturn
gst_gl_base_filter_change_state(GstElement * element,GstStateChange transition)453 gst_gl_base_filter_change_state (GstElement * element,
454 GstStateChange transition)
455 {
456 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (element);
457 GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter);
458 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
459
460 GST_DEBUG_OBJECT (filter, "changing state: %s => %s",
461 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
462 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
463
464 switch (transition) {
465 case GST_STATE_CHANGE_NULL_TO_READY:
466 if (!gst_gl_ensure_element_data (element, &filter->display,
467 &filter->priv->other_context))
468 return GST_STATE_CHANGE_FAILURE;
469
470 gst_gl_display_filter_gl_api (filter->display,
471 filter_class->supported_gl_api);
472 break;
473 default:
474 break;
475 }
476
477 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
478 if (ret == GST_STATE_CHANGE_FAILURE)
479 return ret;
480
481 switch (transition) {
482 case GST_STATE_CHANGE_READY_TO_NULL:
483 g_rec_mutex_lock (&filter->priv->context_lock);
484 gst_clear_object (&filter->priv->other_context);
485 gst_clear_object (&filter->display);
486 gst_clear_object (&filter->context);
487 g_rec_mutex_unlock (&filter->priv->context_lock);
488 break;
489 default:
490 break;
491 }
492
493 return ret;
494 }
495
496 static void
gst_gl_base_filter_set_context(GstElement * element,GstContext * context)497 gst_gl_base_filter_set_context (GstElement * element, GstContext * context)
498 {
499 GstGLBaseFilter *filter = GST_GL_BASE_FILTER (element);
500 GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter);
501 GstGLDisplay *old_display, *new_display;
502
503 g_rec_mutex_lock (&filter->priv->context_lock);
504 old_display = filter->display ? gst_object_ref (filter->display) : NULL;
505 gst_gl_handle_set_context (element, context, &filter->display,
506 &filter->priv->other_context);
507 if (filter->display)
508 gst_gl_display_filter_gl_api (filter->display,
509 filter_class->supported_gl_api);
510 new_display = filter->display ? gst_object_ref (filter->display) : NULL;
511
512 if (old_display && new_display) {
513 if (old_display != new_display) {
514 gst_clear_object (&filter->context);
515 if (gst_gl_base_filter_find_gl_context_unlocked (filter)) {
516 if (filter->in_caps && filter->out_caps) {
517 gl_set_caps_unlocked (filter);
518 }
519 }
520 }
521 }
522 g_rec_mutex_unlock (&filter->priv->context_lock);
523 gst_clear_object (&old_display);
524 gst_clear_object (&new_display);
525
526 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
527 }
528
529 static gboolean
gst_gl_base_filter_find_gl_context_unlocked(GstGLBaseFilter * filter)530 gst_gl_base_filter_find_gl_context_unlocked (GstGLBaseFilter * filter)
531 {
532 GstGLBaseFilterClass *filter_class = GST_GL_BASE_FILTER_GET_CLASS (filter);
533 GError *error = NULL;
534 gboolean new_context = FALSE;
535
536 GST_DEBUG_OBJECT (filter, "attempting to find an OpenGL context, existing %"
537 GST_PTR_FORMAT, filter->context);
538
539 if (!filter->context)
540 new_context = TRUE;
541
542 _find_local_gl_context_unlocked (filter);
543
544 if (!filter->display) {
545 GST_WARNING_OBJECT (filter, "filter has NULL display.");
546 return FALSE;
547 }
548
549 if (!filter->context) {
550 GST_OBJECT_LOCK (filter->display);
551 do {
552 if (filter->context)
553 gst_object_unref (filter->context);
554 /* just get a GL context. we don't care */
555 filter->context =
556 gst_gl_display_get_gl_context_for_thread (filter->display, NULL);
557 if (!filter->context) {
558 if (!gst_gl_display_create_context (filter->display,
559 filter->priv->other_context, &filter->context, &error)) {
560 GST_OBJECT_UNLOCK (filter->display);
561 goto context_error;
562 }
563 }
564 } while (!gst_gl_display_add_context (filter->display, filter->context));
565 GST_OBJECT_UNLOCK (filter->display);
566 }
567 GST_INFO_OBJECT (filter, "found OpenGL context %" GST_PTR_FORMAT,
568 filter->context);
569
570 if (new_context || !filter->priv->gl_started) {
571 if (filter->priv->gl_started)
572 gst_gl_context_thread_add (filter->context, gst_gl_base_filter_gl_stop,
573 filter);
574
575 {
576 GstGLAPI current_gl_api = gst_gl_context_get_gl_api (filter->context);
577 if ((current_gl_api & filter_class->supported_gl_api) == 0)
578 goto unsupported_gl_api;
579 }
580
581 gst_gl_context_thread_add (filter->context, gst_gl_base_filter_gl_start,
582 filter);
583
584 if (!filter->priv->gl_started)
585 goto error;
586 }
587
588 return TRUE;
589
590 unsupported_gl_api:
591 {
592 GstGLAPI gl_api = gst_gl_context_get_gl_api (filter->context);
593 gchar *gl_api_str = gst_gl_api_to_string (gl_api);
594 gchar *supported_gl_api_str =
595 gst_gl_api_to_string (filter_class->supported_gl_api);
596
597 GST_ELEMENT_ERROR (filter, RESOURCE, BUSY,
598 ("GL API's not compatible context: %s supported: %s", gl_api_str,
599 supported_gl_api_str), (NULL));
600
601 g_free (supported_gl_api_str);
602 g_free (gl_api_str);
603 return FALSE;
604 }
605 context_error:
606 {
607 GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND, ("%s", error->message),
608 (NULL));
609 g_clear_error (&error);
610 return FALSE;
611 }
612 error:
613 {
614 GST_ELEMENT_ERROR (filter, LIBRARY, INIT,
615 ("Subclass failed to initialize."), (NULL));
616 return FALSE;
617 }
618 }
619
620 /**
621 * gst_gl_base_filter_find_gl_context:
622 * @filter: a #GstGLBaseFilter
623 *
624 * Returns: Whether an OpenGL context could be retrieved or created successfully
625 *
626 * Since: 1.16
627 */
628 gboolean
gst_gl_base_filter_find_gl_context(GstGLBaseFilter * filter)629 gst_gl_base_filter_find_gl_context (GstGLBaseFilter * filter)
630 {
631 gboolean ret;
632 g_rec_mutex_lock (&filter->priv->context_lock);
633 ret = gst_gl_base_filter_find_gl_context_unlocked (filter);
634 g_rec_mutex_unlock (&filter->priv->context_lock);
635 return ret;
636 }
637
638 /**
639 * gst_gl_base_filter_get_gl_context:
640 * @filter: a #GstGLBaseFilter
641 *
642 * Returns: (transfer full) (nullable): the #GstGLContext found by @filter
643 *
644 * Since: 1.18
645 */
646 GstGLContext *
gst_gl_base_filter_get_gl_context(GstGLBaseFilter * filter)647 gst_gl_base_filter_get_gl_context (GstGLBaseFilter * filter)
648 {
649 GstGLContext *ret;
650
651 g_return_val_if_fail (GST_IS_GL_BASE_FILTER (filter), NULL);
652
653 g_rec_mutex_lock (&filter->priv->context_lock);
654 ret = filter->context ? gst_object_ref (filter->context) : NULL;
655 g_rec_mutex_unlock (&filter->priv->context_lock);
656 return ret;
657 }
658