1 /* Generic video mixer plugin
2 *
3 * GStreamer
4 * Copyright (C) 2015 Matthew Waters <matthew@centricular.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/video/video.h>
28
29 #include "gstglbasemixer.h"
30
31 #define GST_CAT_DEFAULT gst_gl_base_mixer_debug
32 GST_DEBUG_CATEGORY (gst_gl_base_mixer_debug);
33
34 static void gst_gl_base_mixer_pad_get_property (GObject * object, guint prop_id,
35 GValue * value, GParamSpec * pspec);
36 static void gst_gl_base_mixer_pad_set_property (GObject * object, guint prop_id,
37 const GValue * value, GParamSpec * pspec);
38
39 static void gst_gl_base_mixer_set_context (GstElement * element,
40 GstContext * context);
41 static GstStateChangeReturn gst_gl_base_mixer_change_state (GstElement *
42 element, GstStateChange transition);
43
44 static void gst_gl_base_mixer_gl_start (GstGLContext * context, gpointer data);
45 static void gst_gl_base_mixer_gl_stop (GstGLContext * context, gpointer data);
46
47 struct _GstGLBaseMixerPrivate
48 {
49 gboolean negotiated;
50
51 GstGLContext *other_context;
52
53 gboolean gl_started;
54 gboolean gl_result;
55
56 GRecMutex context_lock;
57 };
58
59 #define gst_gl_base_mixer_parent_class parent_class
60 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GstGLBaseMixer, gst_gl_base_mixer,
61 GST_TYPE_VIDEO_AGGREGATOR);
62
63 G_DEFINE_TYPE (GstGLBaseMixerPad, gst_gl_base_mixer_pad,
64 GST_TYPE_VIDEO_AGGREGATOR_PAD);
65
66 static void
gst_gl_base_mixer_pad_class_init(GstGLBaseMixerPadClass * klass)67 gst_gl_base_mixer_pad_class_init (GstGLBaseMixerPadClass * klass)
68 {
69 GObjectClass *gobject_class = (GObjectClass *) klass;
70 GstVideoAggregatorPadClass *vaggpad_class =
71 (GstVideoAggregatorPadClass *) klass;
72
73 gobject_class->set_property = gst_gl_base_mixer_pad_set_property;
74 gobject_class->get_property = gst_gl_base_mixer_pad_get_property;
75
76 vaggpad_class->prepare_frame = NULL;
77 vaggpad_class->clean_frame = NULL;
78
79 gst_type_mark_as_plugin_api (GST_TYPE_GL_BASE_MIXER_PAD, 0);
80 }
81
82 static void
gst_gl_base_mixer_pad_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)83 gst_gl_base_mixer_pad_get_property (GObject * object, guint prop_id,
84 GValue * value, GParamSpec * pspec)
85 {
86 switch (prop_id) {
87 default:
88 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
89 break;
90 }
91 }
92
93 static void
gst_gl_base_mixer_pad_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)94 gst_gl_base_mixer_pad_set_property (GObject * object, guint prop_id,
95 const GValue * value, GParamSpec * pspec)
96 {
97 switch (prop_id) {
98 default:
99 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
100 break;
101 }
102 }
103
104 static gboolean
_find_local_gl_context_unlocked(GstGLBaseMixer * mix)105 _find_local_gl_context_unlocked (GstGLBaseMixer * mix)
106 {
107 GstGLContext *context, *prev_context;
108 gboolean ret;
109
110 if (mix->context && mix->context->display == mix->display)
111 return TRUE;
112
113 context = prev_context = mix->context;
114 g_rec_mutex_unlock (&mix->priv->context_lock);
115 /* we need to drop the lock to query as another element may also be
116 * performing a context query on us which would also attempt to take the
117 * context_lock. Our query could block on the same lock in the other element.
118 */
119 ret =
120 gst_gl_query_local_gl_context (GST_ELEMENT (mix), GST_PAD_SRC, &context);
121 g_rec_mutex_lock (&mix->priv->context_lock);
122 if (ret) {
123 if (mix->context != prev_context) {
124 /* we need to recheck everything since we dropped the lock and the
125 * context has changed */
126 if (mix->context && mix->context->display == mix->display) {
127 if (context != mix->context)
128 gst_clear_object (&context);
129 return TRUE;
130 }
131 }
132
133 if (context->display == mix->display) {
134 mix->context = context;
135 return TRUE;
136 }
137 if (context != mix->context)
138 gst_clear_object (&context);
139 }
140
141 context = prev_context = mix->context;
142 g_rec_mutex_unlock (&mix->priv->context_lock);
143 /* we need to drop the lock to query as another element may also be
144 * performing a context query on us which would also attempt to take the
145 * context_lock. Our query could block on the same lock in the other element.
146 */
147 ret =
148 gst_gl_query_local_gl_context (GST_ELEMENT (mix), GST_PAD_SINK, &context);
149 g_rec_mutex_lock (&mix->priv->context_lock);
150 if (ret) {
151 if (mix->context != prev_context) {
152 /* we need to recheck everything now that we dropped the lock */
153 if (mix->context && mix->context->display == mix->display) {
154 if (context != mix->context)
155 gst_clear_object (&context);
156 return TRUE;
157 }
158 }
159
160 if (context->display == mix->display) {
161 mix->context = context;
162 return TRUE;
163 }
164 if (context != mix->context)
165 gst_clear_object (&context);
166 }
167
168 return FALSE;
169 }
170
171 static gboolean
_get_gl_context_unlocked(GstGLBaseMixer * mix)172 _get_gl_context_unlocked (GstGLBaseMixer * mix)
173 {
174 GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
175 gboolean new_context = FALSE;
176 GError *error = NULL;
177
178 if (!mix->context)
179 new_context = TRUE;
180
181 if (!gst_gl_ensure_element_data (mix, &mix->display,
182 &mix->priv->other_context))
183 return FALSE;
184
185 gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
186
187 _find_local_gl_context_unlocked (mix);
188
189 GST_OBJECT_LOCK (mix->display);
190 if (!mix->context) {
191 do {
192 if (mix->context) {
193 gst_object_unref (mix->context);
194 mix->context = NULL;
195 }
196 /* just get a GL context. we don't care */
197 mix->context =
198 gst_gl_display_get_gl_context_for_thread (mix->display, NULL);
199 if (!mix->context) {
200 if (!gst_gl_display_create_context (mix->display,
201 mix->priv->other_context, &mix->context, &error)) {
202 GST_OBJECT_UNLOCK (mix->display);
203 goto context_error;
204 }
205 }
206 } while (!gst_gl_display_add_context (mix->display, mix->context));
207 }
208 GST_OBJECT_UNLOCK (mix->display);
209
210 if (new_context || !mix->priv->gl_started) {
211 if (mix->priv->gl_started)
212 gst_gl_context_thread_add (mix->context, gst_gl_base_mixer_gl_stop, mix);
213
214 {
215 if ((gst_gl_context_get_gl_api (mix->
216 context) & mix_class->supported_gl_api) == 0)
217 goto unsupported_gl_api;
218 }
219
220 gst_gl_context_thread_add (mix->context, gst_gl_base_mixer_gl_start, mix);
221
222 if (!mix->priv->gl_started)
223 goto error;
224 }
225
226 return TRUE;
227
228 unsupported_gl_api:
229 {
230 GstGLAPI gl_api = gst_gl_context_get_gl_api (mix->context);
231 gchar *gl_api_str = gst_gl_api_to_string (gl_api);
232 gchar *supported_gl_api_str =
233 gst_gl_api_to_string (mix_class->supported_gl_api);
234 GST_ELEMENT_ERROR (mix, RESOURCE, BUSY,
235 ("GL API's not compatible context: %s supported: %s", gl_api_str,
236 supported_gl_api_str), (NULL));
237
238 g_free (supported_gl_api_str);
239 g_free (gl_api_str);
240 return FALSE;
241 }
242 context_error:
243 {
244 GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
245 (NULL));
246 g_clear_error (&error);
247 return FALSE;
248 }
249 error:
250 {
251 GST_ELEMENT_ERROR (mix, LIBRARY, INIT,
252 ("Subclass failed to initialize."), (NULL));
253 return FALSE;
254 }
255 }
256
257 static gboolean
_get_gl_context(GstGLBaseMixer * mix)258 _get_gl_context (GstGLBaseMixer * mix)
259 {
260 gboolean ret;
261 g_rec_mutex_lock (&mix->priv->context_lock);
262 ret = _get_gl_context_unlocked (mix);
263 g_rec_mutex_unlock (&mix->priv->context_lock);
264 return ret;
265 }
266
267 static gboolean
gst_gl_base_mixer_propose_allocation(GstAggregator * agg,GstAggregatorPad * aggpad,GstQuery * decide_query,GstQuery * query)268 gst_gl_base_mixer_propose_allocation (GstAggregator * agg,
269 GstAggregatorPad * aggpad, GstQuery * decide_query, GstQuery * query)
270 {
271 GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
272
273 if (!_get_gl_context (mix))
274 return FALSE;
275
276 return TRUE;
277 }
278
279 static gboolean
gst_gl_base_mixer_sink_query(GstAggregator * agg,GstAggregatorPad * bpad,GstQuery * query)280 gst_gl_base_mixer_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
281 GstQuery * query)
282 {
283 GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
284
285 GST_TRACE ("QUERY %" GST_PTR_FORMAT, query);
286
287 switch (GST_QUERY_TYPE (query)) {
288 case GST_QUERY_CONTEXT:
289 {
290 GstGLDisplay *display = NULL;
291 GstGLContext *other = NULL, *local = NULL;
292 gboolean ret;
293
294 g_rec_mutex_lock (&mix->priv->context_lock);
295 if (mix->display)
296 display = gst_object_ref (mix->display);
297 if (mix->context)
298 local = gst_object_ref (mix->context);
299 if (mix->priv->other_context)
300 other = gst_object_ref (mix->priv->other_context);
301 g_rec_mutex_unlock (&mix->priv->context_lock);
302
303 ret = gst_gl_handle_context_query ((GstElement *) mix, query,
304 display, local, other);
305
306 gst_clear_object (&display);
307 gst_clear_object (&other);
308 gst_clear_object (&local);
309
310 if (ret)
311 return ret;
312 break;
313 }
314 default:
315 break;
316 }
317
318 return GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query);;
319 }
320
321 static void
gst_gl_base_mixer_pad_init(GstGLBaseMixerPad * mixerpad)322 gst_gl_base_mixer_pad_init (GstGLBaseMixerPad * mixerpad)
323 {
324 }
325
326 /* GLBaseMixer signals and args */
327 enum
328 {
329 /* FILL ME */
330 LAST_SIGNAL
331 };
332
333 enum
334 {
335 PROP_0,
336 PROP_CONTEXT
337 };
338
339 static gboolean gst_gl_base_mixer_src_query (GstAggregator * agg,
340 GstQuery * query);
341
342 static gboolean
343 gst_gl_base_mixer_src_activate_mode (GstAggregator * aggregator,
344 GstPadMode mode, gboolean active);
345 static gboolean gst_gl_base_mixer_stop (GstAggregator * agg);
346 static gboolean gst_gl_base_mixer_start (GstAggregator * agg);
347
348 static void gst_gl_base_mixer_finalize (GObject * object);
349 static void gst_gl_base_mixer_set_property (GObject * object, guint prop_id,
350 const GValue * value, GParamSpec * pspec);
351 static void gst_gl_base_mixer_get_property (GObject * object, guint prop_id,
352 GValue * value, GParamSpec * pspec);
353
354 static gboolean gst_gl_base_mixer_decide_allocation (GstAggregator * agg,
355 GstQuery * query);
356
357 static gboolean gst_gl_base_mixer_default_gl_start (GstGLBaseMixer * src);
358 static void gst_gl_base_mixer_default_gl_stop (GstGLBaseMixer * src);
359
360 static void
gst_gl_base_mixer_class_init(GstGLBaseMixerClass * klass)361 gst_gl_base_mixer_class_init (GstGLBaseMixerClass * klass)
362 {
363 GObjectClass *gobject_class;
364 GstElementClass *element_class;
365 GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
366
367 GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "opengl mixer");
368
369 gobject_class = (GObjectClass *) klass;
370 element_class = GST_ELEMENT_CLASS (klass);
371
372 gobject_class->finalize = gst_gl_base_mixer_finalize;
373 gobject_class->get_property = gst_gl_base_mixer_get_property;
374 gobject_class->set_property = gst_gl_base_mixer_set_property;
375
376 element_class->set_context =
377 GST_DEBUG_FUNCPTR (gst_gl_base_mixer_set_context);
378 element_class->change_state = gst_gl_base_mixer_change_state;
379
380 agg_class->sink_query = gst_gl_base_mixer_sink_query;
381 agg_class->src_query = gst_gl_base_mixer_src_query;
382 agg_class->src_activate = gst_gl_base_mixer_src_activate_mode;
383 agg_class->stop = gst_gl_base_mixer_stop;
384 agg_class->start = gst_gl_base_mixer_start;
385 agg_class->decide_allocation = gst_gl_base_mixer_decide_allocation;
386 agg_class->propose_allocation = gst_gl_base_mixer_propose_allocation;
387
388 klass->gl_start = gst_gl_base_mixer_default_gl_start;
389 klass->gl_stop = gst_gl_base_mixer_default_gl_stop;
390
391 g_object_class_install_property (gobject_class, PROP_CONTEXT,
392 g_param_spec_object ("context",
393 "OpenGL context",
394 "Get OpenGL context",
395 GST_TYPE_GL_CONTEXT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
396
397 /* Register the pad class */
398 g_type_class_ref (GST_TYPE_GL_BASE_MIXER_PAD);
399
400 klass->supported_gl_api = GST_GL_API_ANY;
401
402 gst_type_mark_as_plugin_api (GST_TYPE_GL_BASE_MIXER, 0);
403 }
404
405 static void
gst_gl_base_mixer_init(GstGLBaseMixer * mix)406 gst_gl_base_mixer_init (GstGLBaseMixer * mix)
407 {
408 mix->priv = gst_gl_base_mixer_get_instance_private (mix);
409
410 g_rec_mutex_init (&mix->priv->context_lock);
411 }
412
413 static void
gst_gl_base_mixer_finalize(GObject * object)414 gst_gl_base_mixer_finalize (GObject * object)
415 {
416 GstGLBaseMixer *mix = GST_GL_BASE_MIXER (object);
417
418 g_rec_mutex_clear (&mix->priv->context_lock);
419
420 G_OBJECT_CLASS (parent_class)->finalize (object);
421 }
422
423 static gboolean
gst_gl_base_mixer_default_gl_start(GstGLBaseMixer * src)424 gst_gl_base_mixer_default_gl_start (GstGLBaseMixer * src)
425 {
426 return TRUE;
427 }
428
429 static void
gst_gl_base_mixer_gl_start(GstGLContext * context,gpointer data)430 gst_gl_base_mixer_gl_start (GstGLContext * context, gpointer data)
431 {
432 GstGLBaseMixer *src = GST_GL_BASE_MIXER (data);
433 GstGLBaseMixerClass *src_class = GST_GL_BASE_MIXER_GET_CLASS (src);
434
435 GST_INFO_OBJECT (src, "starting");
436 gst_gl_insert_debug_marker (src->context,
437 "starting element %s", GST_OBJECT_NAME (src));
438
439 src->priv->gl_started = src_class->gl_start (src);
440 }
441
442 static void
gst_gl_base_mixer_default_gl_stop(GstGLBaseMixer * src)443 gst_gl_base_mixer_default_gl_stop (GstGLBaseMixer * src)
444 {
445 }
446
447 static void
gst_gl_base_mixer_gl_stop(GstGLContext * context,gpointer data)448 gst_gl_base_mixer_gl_stop (GstGLContext * context, gpointer data)
449 {
450 GstGLBaseMixer *src = GST_GL_BASE_MIXER (data);
451 GstGLBaseMixerClass *src_class = GST_GL_BASE_MIXER_GET_CLASS (src);
452
453 GST_INFO_OBJECT (src, "stopping");
454 gst_gl_insert_debug_marker (src->context,
455 "stopping element %s", GST_OBJECT_NAME (src));
456
457 if (src->priv->gl_started)
458 src_class->gl_stop (src);
459
460 src->priv->gl_started = FALSE;
461 }
462
463 static void
gst_gl_base_mixer_set_context(GstElement * element,GstContext * context)464 gst_gl_base_mixer_set_context (GstElement * element, GstContext * context)
465 {
466 GstGLBaseMixer *mix = GST_GL_BASE_MIXER (element);
467 GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
468 GstGLDisplay *old_display, *new_display;
469
470 g_rec_mutex_lock (&mix->priv->context_lock);
471 old_display = mix->display ? gst_object_ref (mix->display) : NULL;
472 gst_gl_handle_set_context (element, context, &mix->display,
473 &mix->priv->other_context);
474 if (mix->display)
475 gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
476 new_display = mix->display ? gst_object_ref (mix->display) : NULL;
477
478 if (old_display && new_display) {
479 if (old_display != new_display) {
480 gst_clear_object (&mix->context);
481 _get_gl_context_unlocked (mix);
482 gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (mix));
483 }
484 }
485 gst_clear_object (&old_display);
486 gst_clear_object (&new_display);
487 g_rec_mutex_unlock (&mix->priv->context_lock);
488
489 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
490 }
491
492 static gboolean
gst_gl_base_mixer_activate(GstGLBaseMixer * mix,gboolean active)493 gst_gl_base_mixer_activate (GstGLBaseMixer * mix, gboolean active)
494 {
495 GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
496 gboolean result = TRUE;
497
498 if (active) {
499 g_rec_mutex_lock (&mix->priv->context_lock);
500 if (!gst_gl_ensure_element_data (mix, &mix->display,
501 &mix->priv->other_context)) {
502 g_rec_mutex_unlock (&mix->priv->context_lock);
503 return FALSE;
504 }
505
506 gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
507 g_rec_mutex_unlock (&mix->priv->context_lock);
508 }
509
510 return result;
511 }
512
513 static gboolean
gst_gl_base_mixer_src_activate_mode(GstAggregator * aggregator,GstPadMode mode,gboolean active)514 gst_gl_base_mixer_src_activate_mode (GstAggregator * aggregator,
515 GstPadMode mode, gboolean active)
516 {
517 GstGLBaseMixer *mix;
518 gboolean result = FALSE;
519
520 mix = GST_GL_BASE_MIXER (aggregator);
521
522 switch (mode) {
523 case GST_PAD_MODE_PUSH:
524 case GST_PAD_MODE_PULL:
525 result = gst_gl_base_mixer_activate (mix, active);
526 break;
527 default:
528 result = TRUE;
529 break;
530 }
531 return result;
532 }
533
534 static gboolean
gst_gl_base_mixer_src_query(GstAggregator * agg,GstQuery * query)535 gst_gl_base_mixer_src_query (GstAggregator * agg, GstQuery * query)
536 {
537 GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
538
539 switch (GST_QUERY_TYPE (query)) {
540 case GST_QUERY_CONTEXT:
541 {
542 GstGLDisplay *display = NULL;
543 GstGLContext *other = NULL, *local = NULL;
544 gboolean ret;
545
546 g_rec_mutex_lock (&mix->priv->context_lock);
547 if (mix->display)
548 display = gst_object_ref (mix->display);
549 if (mix->context)
550 local = gst_object_ref (mix->context);
551 if (mix->priv->other_context)
552 other = gst_object_ref (mix->priv->other_context);
553 g_rec_mutex_unlock (&mix->priv->context_lock);
554
555 ret = gst_gl_handle_context_query ((GstElement *) mix, query,
556 display, local, other);
557
558 gst_clear_object (&display);
559 gst_clear_object (&other);
560 gst_clear_object (&local);
561
562 if (ret)
563 return ret;
564 break;
565 }
566 default:
567 break;
568 }
569
570 return GST_AGGREGATOR_CLASS (parent_class)->src_query (agg, query);
571 }
572
573 static gboolean
gst_gl_base_mixer_decide_allocation(GstAggregator * agg,GstQuery * query)574 gst_gl_base_mixer_decide_allocation (GstAggregator * agg, GstQuery * query)
575 {
576 GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
577
578 if (!_get_gl_context (mix))
579 return FALSE;
580
581 return TRUE;
582 }
583
584 static void
gst_gl_base_mixer_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)585 gst_gl_base_mixer_get_property (GObject * object,
586 guint prop_id, GValue * value, GParamSpec * pspec)
587 {
588 GstGLBaseMixer *mixer = GST_GL_BASE_MIXER (object);
589
590 switch (prop_id) {
591 case PROP_CONTEXT:
592 g_value_set_object (value, mixer->context);
593 break;
594 default:
595 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
596 break;
597 }
598 }
599
600 static void
gst_gl_base_mixer_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)601 gst_gl_base_mixer_set_property (GObject * object,
602 guint prop_id, const GValue * value, GParamSpec * pspec)
603 {
604 switch (prop_id) {
605 default:
606 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
607 break;
608 }
609 }
610
611 static gboolean
gst_gl_base_mixer_start(GstAggregator * agg)612 gst_gl_base_mixer_start (GstAggregator * agg)
613 {
614 return GST_AGGREGATOR_CLASS (parent_class)->start (agg);;
615 }
616
617 static gboolean
gst_gl_base_mixer_stop(GstAggregator * agg)618 gst_gl_base_mixer_stop (GstAggregator * agg)
619 {
620 GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
621
622 g_rec_mutex_lock (&mix->priv->context_lock);
623 if (mix->priv->gl_started)
624 gst_gl_context_thread_add (mix->context, gst_gl_base_mixer_gl_stop, mix);
625 gst_clear_object (&mix->context);
626 g_rec_mutex_unlock (&mix->priv->context_lock);
627
628 return TRUE;
629 }
630
631 static GstStateChangeReturn
gst_gl_base_mixer_change_state(GstElement * element,GstStateChange transition)632 gst_gl_base_mixer_change_state (GstElement * element, GstStateChange transition)
633 {
634 GstGLBaseMixer *mix = GST_GL_BASE_MIXER (element);
635 GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix);
636 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
637
638 GST_DEBUG_OBJECT (mix, "changing state: %s => %s",
639 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
640 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
641
642 switch (transition) {
643 case GST_STATE_CHANGE_NULL_TO_READY:
644 if (!gst_gl_ensure_element_data (element, &mix->display,
645 &mix->priv->other_context))
646 return GST_STATE_CHANGE_FAILURE;
647
648 gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api);
649 break;
650 default:
651 break;
652 }
653
654 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
655 if (ret == GST_STATE_CHANGE_FAILURE)
656 return ret;
657
658 switch (transition) {
659 case GST_STATE_CHANGE_READY_TO_NULL:
660 if (mix->priv->other_context) {
661 gst_object_unref (mix->priv->other_context);
662 mix->priv->other_context = NULL;
663 }
664
665 g_rec_mutex_lock (&mix->priv->context_lock);
666 gst_clear_object (&mix->display);
667 g_rec_mutex_unlock (&mix->priv->context_lock);
668 break;
669 default:
670 break;
671 }
672
673 return ret;
674 }
675
676 /**
677 * gst_gl_base_mixer_get_gl_context:
678 * @mix: a #GstGLBaseMixer
679 *
680 * Returns: (transfer full) (nullable): the #GstGLContext found by @mix
681 *
682 * Since: 1.18
683 */
684 GstGLContext *
gst_gl_base_mixer_get_gl_context(GstGLBaseMixer * mix)685 gst_gl_base_mixer_get_gl_context (GstGLBaseMixer * mix)
686 {
687 GstGLContext *ret;
688
689 g_return_val_if_fail (GST_IS_GL_BASE_MIXER (mix), NULL);
690
691 g_rec_mutex_lock (&mix->priv->context_lock);
692 ret = mix->context ? gst_object_ref (mix->context) : NULL;
693 g_rec_mutex_unlock (&mix->priv->context_lock);
694 return ret;
695 }
696