• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/videooverlay.h>
26 #include <gst/video/navigation.h>
27 #include <gst/controller/gstproxycontrolbinding.h>
28 
29 #include "gstglelements.h"
30 #include "gstglsinkbin.h"
31 
32 GST_DEBUG_CATEGORY (gst_debug_gl_sink_bin);
33 #define GST_CAT_DEFAULT gst_debug_gl_sink_bin
34 
35 static void gst_gl_sink_bin_finalize (GObject * object);
36 static void gst_gl_sink_bin_set_property (GObject * object, guint prop_id,
37     const GValue * value, GParamSpec * param_spec);
38 static void gst_gl_sink_bin_get_property (GObject * object, guint prop_id,
39     GValue * value, GParamSpec * param_spec);
40 
41 static GstStateChangeReturn gst_gl_sink_bin_change_state (GstElement * element,
42     GstStateChange transition);
43 
44 static void gst_gl_sink_bin_video_overlay_init (gpointer g_iface,
45     gpointer g_iface_data);
46 static void gst_gl_sink_bin_navigation_interface_init (gpointer g_iface,
47     gpointer g_iface_data);
48 static void gst_gl_sink_bin_color_balance_init (gpointer g_iface,
49     gpointer g_iface_data);
50 
51 #define DEFAULT_SYNC                TRUE
52 #define DEFAULT_MAX_LATENESS        -1
53 #define DEFAULT_QOS                 FALSE
54 #define DEFAULT_ASYNC               TRUE
55 #define DEFAULT_TS_OFFSET           0
56 #define DEFAULT_BLOCKSIZE           4096
57 #define DEFAULT_RENDER_DELAY        0
58 #define DEFAULT_ENABLE_LAST_SAMPLE  TRUE
59 #define DEFAULT_THROTTLE_TIME       0
60 #define DEFAULT_MAX_BITRATE         0
61 
62 /* GstGLColorBalance properties */
63 #define DEFAULT_PROP_CONTRAST       1.0
64 #define DEFAULT_PROP_BRIGHTNESS	    0.0
65 #define DEFAULT_PROP_HUE            0.0
66 #define DEFAULT_PROP_SATURATION	    1.0
67 
68 enum
69 {
70   PROP_0,
71   PROP_FORCE_ASPECT_RATIO,
72   PROP_SINK,
73   PROP_SYNC,
74   PROP_MAX_LATENESS,
75   PROP_QOS,
76   PROP_ASYNC,
77   PROP_TS_OFFSET,
78   PROP_ENABLE_LAST_SAMPLE,
79   PROP_LAST_SAMPLE,
80   PROP_BLOCKSIZE,
81   PROP_RENDER_DELAY,
82   PROP_THROTTLE_TIME,
83   PROP_MAX_BITRATE,
84   PROP_CONTRAST,
85   PROP_BRIGHTNESS,
86   PROP_HUE,
87   PROP_SATURATION,
88 };
89 
90 enum
91 {
92   SIGNAL_0,
93   SIGNAL_CREATE_ELEMENT,
94   SIGNAL_LAST,
95 };
96 
97 static guint gst_gl_sink_bin_signals[SIGNAL_LAST] = { 0, };
98 
99 #define gst_gl_sink_bin_parent_class parent_class
100 G_DEFINE_TYPE_WITH_CODE (GstGLSinkBin, gst_gl_sink_bin,
101     GST_TYPE_BIN, G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
102         gst_gl_sink_bin_video_overlay_init);
103     G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
104         gst_gl_sink_bin_navigation_interface_init);
105     G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
106         gst_gl_sink_bin_color_balance_init)
107     GST_DEBUG_CATEGORY_INIT (gst_debug_gl_sink_bin, "glimagesink", 0,
108         "OpenGL Video Sink Bin"));
109 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (glsinkbin, "glsinkbin",
110     GST_RANK_NONE, GST_TYPE_GL_SINK_BIN, gl_element_init (plugin));
111 
112 static void
gst_gl_sink_bin_class_init(GstGLSinkBinClass * klass)113 gst_gl_sink_bin_class_init (GstGLSinkBinClass * klass)
114 {
115   GObjectClass *gobject_class;
116   GstElementClass *element_class;
117   GstCaps *upload_caps;
118 
119   gobject_class = (GObjectClass *) klass;
120   element_class = GST_ELEMENT_CLASS (klass);
121 
122   element_class->change_state = gst_gl_sink_bin_change_state;
123 
124   gobject_class->set_property = gst_gl_sink_bin_set_property;
125   gobject_class->get_property = gst_gl_sink_bin_get_property;
126   gobject_class->finalize = gst_gl_sink_bin_finalize;
127 
128   g_object_class_install_property (gobject_class, PROP_FORCE_ASPECT_RATIO,
129       g_param_spec_boolean ("force-aspect-ratio",
130           "Force aspect ratio",
131           "When enabled, scaling will respect original aspect ratio", TRUE,
132           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
133   g_object_class_install_property (gobject_class, PROP_SINK,
134       g_param_spec_object ("sink",
135           "GL sink element",
136           "The GL sink chain to use",
137           GST_TYPE_ELEMENT,
138           GST_PARAM_MUTABLE_READY | G_PARAM_READWRITE |
139           G_PARAM_STATIC_STRINGS));
140 
141   /* base sink */
142   g_object_class_install_property (gobject_class, PROP_SYNC,
143       g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
144           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
145   g_object_class_install_property (gobject_class, PROP_MAX_LATENESS,
146       g_param_spec_int64 ("max-lateness", "Max Lateness",
147           "Maximum number of nanoseconds that a buffer can be late before it "
148           "is dropped (-1 unlimited)", -1, G_MAXINT64, DEFAULT_MAX_LATENESS,
149           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
150   g_object_class_install_property (gobject_class, PROP_QOS,
151       g_param_spec_boolean ("qos", "Qos",
152           "Generate Quality-of-Service events upstream", DEFAULT_QOS,
153           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
154   g_object_class_install_property (gobject_class, PROP_ASYNC,
155       g_param_spec_boolean ("async", "Async",
156           "Go asynchronously to PAUSED", DEFAULT_ASYNC,
157           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
158   g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
159       g_param_spec_int64 ("ts-offset", "TS Offset",
160           "Timestamp offset in nanoseconds", G_MININT64, G_MAXINT64,
161           DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
162   g_object_class_install_property (gobject_class, PROP_ENABLE_LAST_SAMPLE,
163       g_param_spec_boolean ("enable-last-sample", "Enable Last Buffer",
164           "Enable the last-sample property", DEFAULT_ENABLE_LAST_SAMPLE,
165           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
166   g_object_class_install_property (gobject_class, PROP_LAST_SAMPLE,
167       g_param_spec_boxed ("last-sample", "Last Sample",
168           "The last sample received in the sink", GST_TYPE_SAMPLE,
169           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
170   g_object_class_install_property (gobject_class, PROP_BLOCKSIZE,
171       g_param_spec_uint ("blocksize", "Block size",
172           "Size in bytes to pull per buffer (0 = default)", 0, G_MAXUINT,
173           DEFAULT_BLOCKSIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
174   g_object_class_install_property (gobject_class, PROP_RENDER_DELAY,
175       g_param_spec_uint64 ("render-delay", "Render Delay",
176           "Additional render delay of the sink in nanoseconds", 0, G_MAXUINT64,
177           DEFAULT_RENDER_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
178   g_object_class_install_property (gobject_class, PROP_THROTTLE_TIME,
179       g_param_spec_uint64 ("throttle-time", "Throttle time",
180           "The time to keep between rendered buffers (0 = disabled)", 0,
181           G_MAXUINT64, DEFAULT_THROTTLE_TIME,
182           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
183   g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
184       g_param_spec_uint64 ("max-bitrate", "Max Bitrate",
185           "The maximum bits per second to render (0 = disabled)", 0,
186           G_MAXUINT64, DEFAULT_MAX_BITRATE,
187           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
188 
189   /* colorbalance */
190   g_object_class_install_property (gobject_class, PROP_CONTRAST,
191       g_param_spec_double ("contrast", "Contrast", "contrast",
192           0.0, 2.0, DEFAULT_PROP_CONTRAST,
193           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
194   g_object_class_install_property (gobject_class, PROP_BRIGHTNESS,
195       g_param_spec_double ("brightness", "Brightness", "brightness", -1.0, 1.0,
196           DEFAULT_PROP_BRIGHTNESS,
197           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
198   g_object_class_install_property (gobject_class, PROP_HUE,
199       g_param_spec_double ("hue", "Hue", "hue", -1.0, 1.0, DEFAULT_PROP_HUE,
200           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201   g_object_class_install_property (gobject_class, PROP_SATURATION,
202       g_param_spec_double ("saturation", "Saturation", "saturation", 0.0, 2.0,
203           DEFAULT_PROP_SATURATION,
204           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
205 
206   /**
207    * GstGLSinkBin::create-element:
208    * @object: the #glsinkbin
209    *
210    * Will be emitted when we need the processing element/s that this bin will use
211    *
212    * Returns: a new #GstElement
213    */
214   gst_gl_sink_bin_signals[SIGNAL_CREATE_ELEMENT] =
215       g_signal_new ("create-element", G_TYPE_FROM_CLASS (klass),
216       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, GST_TYPE_ELEMENT, 0);
217 
218   gst_element_class_set_metadata (element_class,
219       "GL Sink Bin", "Sink/Video",
220       "Infrastructure to process GL textures",
221       "Matthew Waters <matthew@centricular.com>");
222 
223   upload_caps = gst_gl_upload_get_input_template_caps ();
224   gst_element_class_add_pad_template (element_class,
225       gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, upload_caps));
226   gst_caps_unref (upload_caps);
227 }
228 
229 static void
gst_gl_sink_bin_init(GstGLSinkBin * self)230 gst_gl_sink_bin_init (GstGLSinkBin * self)
231 {
232   gboolean res = TRUE;
233   GstPad *pad;
234 
235   self->upload = gst_element_factory_make ("glupload", NULL);
236   self->convert = gst_element_factory_make ("glcolorconvert", NULL);
237   self->balance = gst_element_factory_make ("glcolorbalance", NULL);
238 
239   res &= gst_bin_add (GST_BIN (self), self->upload);
240   res &= gst_bin_add (GST_BIN (self), self->convert);
241   res &= gst_bin_add (GST_BIN (self), self->balance);
242 
243   res &= gst_element_link_pads (self->upload, "src", self->convert, "sink");
244   res &= gst_element_link_pads (self->convert, "src", self->balance, "sink");
245 
246   pad = gst_element_get_static_pad (self->upload, "sink");
247   if (!pad) {
248     res = FALSE;
249   } else {
250     GST_DEBUG_OBJECT (self, "setting target sink pad %" GST_PTR_FORMAT, pad);
251     self->sinkpad = gst_ghost_pad_new ("sink", pad);
252     gst_element_add_pad (GST_ELEMENT_CAST (self), self->sinkpad);
253     gst_object_unref (pad);
254   }
255 
256 #define ADD_BINDING(obj,ref,prop) \
257     gst_object_add_control_binding (GST_OBJECT (obj), \
258         gst_proxy_control_binding_new (GST_OBJECT (obj), prop, \
259             GST_OBJECT (ref), prop));
260   ADD_BINDING (self->balance, self, "contrast");
261   ADD_BINDING (self->balance, self, "brightness");
262   ADD_BINDING (self->balance, self, "hue");
263   ADD_BINDING (self->balance, self, "saturation");
264 #undef ADD_BINDING
265 
266   if (!res) {
267     GST_WARNING_OBJECT (self, "Failed to add/connect the necessary machinery");
268   }
269 }
270 
271 static void
gst_gl_sink_bin_finalize(GObject * object)272 gst_gl_sink_bin_finalize (GObject * object)
273 {
274   GstGLSinkBin *self = GST_GL_SINK_BIN (object);
275 
276   if (self->sink)
277     gst_object_unref (self->sink);
278 
279   G_OBJECT_CLASS (parent_class)->finalize (object);
280 }
281 
282 static gboolean
_connect_sink_element(GstGLSinkBin * self)283 _connect_sink_element (GstGLSinkBin * self)
284 {
285   gst_object_set_name (GST_OBJECT (self->sink), "sink");
286 
287   if (gst_bin_add (GST_BIN (self), self->sink) &&
288       gst_element_link_pads (self->balance, "src", self->sink, "sink"))
289     return TRUE;
290 
291   GST_ERROR_OBJECT (self, "Failed to link sink element into the pipeline");
292   return FALSE;
293 }
294 
295 /*
296  * @sink: (transfer full):
297  */
298 static gboolean
gst_gl_sink_bin_set_sink(GstGLSinkBin * self,GstElement * sink)299 gst_gl_sink_bin_set_sink (GstGLSinkBin * self, GstElement * sink)
300 {
301   g_return_val_if_fail (GST_IS_ELEMENT (sink), FALSE);
302 
303   if (self->sink) {
304     gst_element_set_locked_state (self->sink, TRUE);
305     gst_bin_remove (GST_BIN (self), self->sink);
306     gst_element_set_state (self->sink, GST_STATE_NULL);
307     gst_object_unref (self->sink);
308     self->sink = NULL;
309   }
310   self->sink = sink;
311 
312   gst_object_ref_sink (sink);
313 
314   if (sink && !_connect_sink_element (self)) {
315     gst_object_unref (self->sink);
316     self->sink = NULL;
317     return FALSE;
318   }
319 
320   return TRUE;
321 }
322 
323 void
gst_gl_sink_bin_finish_init_with_element(GstGLSinkBin * self,GstElement * element)324 gst_gl_sink_bin_finish_init_with_element (GstGLSinkBin * self,
325     GstElement * element)
326 {
327   gst_gl_sink_bin_set_sink (self, element);
328 }
329 
330 void
gst_gl_sink_bin_finish_init(GstGLSinkBin * self)331 gst_gl_sink_bin_finish_init (GstGLSinkBin * self)
332 {
333   GstGLSinkBinClass *klass = GST_GL_SINK_BIN_GET_CLASS (self);
334   GstElement *element = NULL;
335 
336   if (klass->create_element)
337     element = klass->create_element ();
338 
339   if (element)
340     gst_gl_sink_bin_finish_init_with_element (self, element);
341 }
342 
343 static void
gst_gl_sink_bin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)344 gst_gl_sink_bin_set_property (GObject * object, guint prop_id,
345     const GValue * value, GParamSpec * pspec)
346 {
347   GstGLSinkBin *self = GST_GL_SINK_BIN (object);
348   GParamSpec *sink_pspec;
349 
350   switch (prop_id) {
351     case PROP_SINK:
352       gst_gl_sink_bin_set_sink (self, g_value_get_object (value));
353       break;
354     case PROP_CONTRAST:
355     case PROP_BRIGHTNESS:
356     case PROP_HUE:
357     case PROP_SATURATION:
358       if (self->balance)
359         g_object_set_property (G_OBJECT (self->balance), pspec->name, value);
360       break;
361     default:
362       if (self->sink) {
363         sink_pspec =
364             g_object_class_find_property (G_OBJECT_GET_CLASS (self->sink),
365             pspec->name);
366         if (sink_pspec
367             && G_PARAM_SPEC_TYPE (sink_pspec) == G_PARAM_SPEC_TYPE (pspec)) {
368           g_object_set_property (G_OBJECT (self->sink), pspec->name, value);
369         } else {
370           GST_INFO ("Failed to set unmatched property %s", pspec->name);
371         }
372       }
373       break;
374   }
375 }
376 
377 static void
gst_gl_sink_bin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)378 gst_gl_sink_bin_get_property (GObject * object, guint prop_id,
379     GValue * value, GParamSpec * pspec)
380 {
381   GstGLSinkBin *self = GST_GL_SINK_BIN (object);
382 
383   switch (prop_id) {
384     case PROP_SINK:
385       g_value_set_object (value, self->sink);
386       break;
387     case PROP_CONTRAST:
388     case PROP_BRIGHTNESS:
389     case PROP_HUE:
390     case PROP_SATURATION:
391       if (self->balance)
392         g_object_get_property (G_OBJECT (self->balance), pspec->name, value);
393       break;
394     default:
395       if (self->sink)
396         g_object_get_property (G_OBJECT (self->sink), pspec->name, value);
397       break;
398   }
399 }
400 
401 static GstStateChangeReturn
gst_gl_sink_bin_change_state(GstElement * element,GstStateChange transition)402 gst_gl_sink_bin_change_state (GstElement * element, GstStateChange transition)
403 {
404   GstGLSinkBin *self = GST_GL_SINK_BIN (element);
405   GstGLSinkBinClass *klass = GST_GL_SINK_BIN_GET_CLASS (self);
406   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
407 
408   GST_DEBUG ("changing state: %s => %s",
409       gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
410       gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
411 
412   switch (transition) {
413     case GST_STATE_CHANGE_NULL_TO_READY:
414       if (!self->sink) {
415         if (klass->create_element)
416           self->sink = klass->create_element ();
417 
418         if (!self->sink) {
419           g_signal_emit (element,
420               gst_gl_sink_bin_signals[SIGNAL_CREATE_ELEMENT], 0, &self->sink);
421           if (self->sink && g_object_is_floating (self->sink))
422             gst_object_ref_sink (self->sink);
423         }
424 
425         if (!self->sink) {
426           GST_ERROR_OBJECT (element, "Failed to retrieve element");
427           return GST_STATE_CHANGE_FAILURE;
428         }
429         if (!_connect_sink_element (self))
430           return GST_STATE_CHANGE_FAILURE;
431       }
432       break;
433     default:
434       break;
435   }
436 
437   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
438   if (ret == GST_STATE_CHANGE_FAILURE)
439     return ret;
440 
441   switch (transition) {
442     default:
443       break;
444   }
445 
446   return ret;
447 }
448 
449 static void
gst_gl_sink_bin_navigation_send_event(GstNavigation * navigation,GstStructure * structure)450 gst_gl_sink_bin_navigation_send_event (GstNavigation * navigation, GstStructure
451     * structure)
452 {
453   GstGLSinkBin *self = GST_GL_SINK_BIN (navigation);
454   GstElement *nav =
455       gst_bin_get_by_interface (GST_BIN (self), GST_TYPE_NAVIGATION);
456 
457   if (nav) {
458     gst_navigation_send_event (GST_NAVIGATION (nav), structure);
459     structure = NULL;
460     gst_object_unref (nav);
461   } else {
462     GstEvent *event = gst_event_new_navigation (structure);
463     structure = NULL;
464     gst_element_send_event (GST_ELEMENT (self), event);
465   }
466 }
467 
468 static void
gst_gl_sink_bin_navigation_interface_init(gpointer g_iface,gpointer g_iface_data)469 gst_gl_sink_bin_navigation_interface_init (gpointer g_iface,
470     gpointer g_iface_data)
471 {
472   GstNavigationInterface *iface = (GstNavigationInterface *) g_iface;
473   iface->send_event = gst_gl_sink_bin_navigation_send_event;
474 }
475 
476 static void
gst_gl_sink_bin_overlay_expose(GstVideoOverlay * overlay)477 gst_gl_sink_bin_overlay_expose (GstVideoOverlay * overlay)
478 {
479   GstGLSinkBin *self = GST_GL_SINK_BIN (overlay);
480   GstVideoOverlay *overlay_element = NULL;
481 
482   overlay_element =
483       GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (self),
484           GST_TYPE_VIDEO_OVERLAY));
485 
486   if (overlay_element) {
487     gst_video_overlay_expose (overlay_element);
488     gst_object_unref (overlay_element);
489   }
490 }
491 
492 static void
gst_gl_sink_bin_overlay_handle_events(GstVideoOverlay * overlay,gboolean handle_events)493 gst_gl_sink_bin_overlay_handle_events (GstVideoOverlay * overlay,
494     gboolean handle_events)
495 {
496   GstGLSinkBin *self = GST_GL_SINK_BIN (overlay);
497   GstVideoOverlay *overlay_element = NULL;
498 
499   overlay_element =
500       GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (self),
501           GST_TYPE_VIDEO_OVERLAY));
502 
503   if (overlay_element) {
504     gst_video_overlay_handle_events (overlay_element, handle_events);
505     gst_object_unref (overlay_element);
506   }
507 }
508 
509 static void
gst_gl_sink_bin_overlay_set_render_rectangle(GstVideoOverlay * overlay,gint x,gint y,gint width,gint height)510 gst_gl_sink_bin_overlay_set_render_rectangle (GstVideoOverlay * overlay, gint x,
511     gint y, gint width, gint height)
512 {
513   GstGLSinkBin *self = GST_GL_SINK_BIN (overlay);
514   GstVideoOverlay *overlay_element = NULL;
515 
516   overlay_element =
517       GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (self),
518           GST_TYPE_VIDEO_OVERLAY));
519 
520   if (overlay_element) {
521     gst_video_overlay_set_render_rectangle (overlay_element, x, y, width,
522         height);
523     gst_object_unref (overlay_element);
524   }
525 }
526 
527 static void
gst_gl_sink_bin_overlay_set_window_handle(GstVideoOverlay * overlay,guintptr handle)528 gst_gl_sink_bin_overlay_set_window_handle (GstVideoOverlay * overlay,
529     guintptr handle)
530 {
531   GstGLSinkBin *self = GST_GL_SINK_BIN (overlay);
532   GstVideoOverlay *overlay_element = NULL;
533 
534   overlay_element =
535       GST_VIDEO_OVERLAY (gst_bin_get_by_interface (GST_BIN (self),
536           GST_TYPE_VIDEO_OVERLAY));
537 
538   if (overlay_element) {
539     gst_video_overlay_set_window_handle (overlay_element, handle);
540     gst_object_unref (overlay_element);
541   }
542 }
543 
544 static void
gst_gl_sink_bin_video_overlay_init(gpointer g_iface,gpointer g_iface_data)545 gst_gl_sink_bin_video_overlay_init (gpointer g_iface, gpointer g_iface_data)
546 {
547   GstVideoOverlayInterface *iface = (GstVideoOverlayInterface *) g_iface;
548   iface->expose = gst_gl_sink_bin_overlay_expose;
549   iface->handle_events = gst_gl_sink_bin_overlay_handle_events;
550   iface->set_render_rectangle = gst_gl_sink_bin_overlay_set_render_rectangle;
551   iface->set_window_handle = gst_gl_sink_bin_overlay_set_window_handle;
552 }
553 
554 static const GList *
gst_gl_sink_bin_color_balance_list_channels(GstColorBalance * balance)555 gst_gl_sink_bin_color_balance_list_channels (GstColorBalance * balance)
556 {
557   GstGLSinkBin *self = GST_GL_SINK_BIN (balance);
558   GstColorBalance *balance_element = NULL;
559   const GList *list = NULL;
560 
561   balance_element =
562       GST_COLOR_BALANCE (gst_bin_get_by_interface (GST_BIN (self),
563           GST_TYPE_COLOR_BALANCE));
564 
565   if (balance_element) {
566     list = gst_color_balance_list_channels (balance_element);
567     gst_object_unref (balance_element);
568   }
569 
570   return list;
571 }
572 
573 static void
gst_gl_sink_bin_color_balance_set_value(GstColorBalance * balance,GstColorBalanceChannel * channel,gint value)574 gst_gl_sink_bin_color_balance_set_value (GstColorBalance * balance,
575     GstColorBalanceChannel * channel, gint value)
576 {
577   GstGLSinkBin *self = GST_GL_SINK_BIN (balance);
578   GstColorBalance *balance_element = NULL;
579 
580   balance_element =
581       GST_COLOR_BALANCE (gst_bin_get_by_interface (GST_BIN (self),
582           GST_TYPE_COLOR_BALANCE));
583 
584   if (balance_element) {
585     gst_color_balance_set_value (balance_element, channel, value);
586     gst_object_unref (balance_element);
587   }
588 }
589 
590 static gint
gst_gl_sink_bin_color_balance_get_value(GstColorBalance * balance,GstColorBalanceChannel * channel)591 gst_gl_sink_bin_color_balance_get_value (GstColorBalance * balance,
592     GstColorBalanceChannel * channel)
593 {
594   GstGLSinkBin *self = GST_GL_SINK_BIN (balance);
595   GstColorBalance *balance_element = NULL;
596   gint val = 0;
597 
598   balance_element =
599       GST_COLOR_BALANCE (gst_bin_get_by_interface (GST_BIN (self),
600           GST_TYPE_COLOR_BALANCE));
601 
602   if (balance_element) {
603     val = gst_color_balance_get_value (balance_element, channel);
604     gst_object_unref (balance_element);
605   }
606 
607   return val;
608 }
609 
610 static GstColorBalanceType
gst_gl_sink_bin_color_balance_get_balance_type(GstColorBalance * balance)611 gst_gl_sink_bin_color_balance_get_balance_type (GstColorBalance * balance)
612 {
613   GstGLSinkBin *self = GST_GL_SINK_BIN (balance);
614   GstColorBalance *balance_element = NULL;
615   GstColorBalanceType type = 0;
616 
617   balance_element =
618       GST_COLOR_BALANCE (gst_bin_get_by_interface (GST_BIN (self),
619           GST_TYPE_COLOR_BALANCE));
620 
621   if (balance_element) {
622     type = gst_color_balance_get_balance_type (balance_element);
623     gst_object_unref (balance_element);
624   }
625 
626   return type;
627 }
628 
629 static void
gst_gl_sink_bin_color_balance_init(gpointer g_iface,gpointer g_iface_data)630 gst_gl_sink_bin_color_balance_init (gpointer g_iface, gpointer g_iface_data)
631 {
632   GstColorBalanceInterface *iface = (GstColorBalanceInterface *) g_iface;
633 
634   iface->list_channels = gst_gl_sink_bin_color_balance_list_channels;
635   iface->set_value = gst_gl_sink_bin_color_balance_set_value;
636   iface->get_value = gst_gl_sink_bin_color_balance_get_value;
637   iface->get_balance_type = gst_gl_sink_bin_color_balance_get_balance_type;
638 }
639