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