1 /* GStreamer
2 *
3 * Copyright (C) 2014-2015 Sebastian Dröge <sebastian@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 /**
22 * SECTION:gstplayer-videooverlayvideorenderer
23 * @title: GstPlayerVideoOverlayVideoRenderer
24 * @short_description: Player Video Overlay Video Renderer
25 *
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include "gstplayer-video-overlay-video-renderer.h"
33 #include "gstplayer.h"
34
35 #include <gst/video/video.h>
36
37 struct _GstPlayerVideoOverlayVideoRenderer
38 {
39 GObject parent;
40
41 GstVideoOverlay *video_overlay;
42 gpointer window_handle;
43 gint x, y, width, height;
44
45 GstElement *video_sink; /* configured video sink, or NULL */
46 };
47
48 struct _GstPlayerVideoOverlayVideoRendererClass
49 {
50 GObjectClass parent_class;
51 };
52
53 static void
54 gst_player_video_overlay_video_renderer_interface_init
55 (GstPlayerVideoRendererInterface * iface);
56
57 enum
58 {
59 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_0,
60 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE,
61 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK,
62 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST
63 };
64
65 G_DEFINE_TYPE_WITH_CODE (GstPlayerVideoOverlayVideoRenderer,
66 gst_player_video_overlay_video_renderer, G_TYPE_OBJECT,
67 G_IMPLEMENT_INTERFACE (GST_TYPE_PLAYER_VIDEO_RENDERER,
68 gst_player_video_overlay_video_renderer_interface_init));
69
70 static GParamSpec
71 * video_overlay_video_renderer_param_specs
72 [VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST] = { NULL, };
73
74 static void
gst_player_video_overlay_video_renderer_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)75 gst_player_video_overlay_video_renderer_set_property (GObject * object,
76 guint prop_id, const GValue * value, GParamSpec * pspec)
77 {
78 GstPlayerVideoOverlayVideoRenderer *self =
79 GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (object);
80
81 switch (prop_id) {
82 case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE:
83 self->window_handle = g_value_get_pointer (value);
84 if (self->video_overlay)
85 gst_video_overlay_set_window_handle (self->video_overlay,
86 (guintptr) self->window_handle);
87 break;
88 case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK:
89 self->video_sink = gst_object_ref_sink (g_value_get_object (value));
90 break;
91 default:
92 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
93 break;
94 }
95 }
96
97 static void
gst_player_video_overlay_video_renderer_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)98 gst_player_video_overlay_video_renderer_get_property (GObject * object,
99 guint prop_id, GValue * value, GParamSpec * pspec)
100 {
101 GstPlayerVideoOverlayVideoRenderer *self =
102 GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (object);
103
104 switch (prop_id) {
105 case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE:
106 g_value_set_pointer (value, self->window_handle);
107 break;
108 case VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK:
109 g_value_set_object (value, self->video_sink);
110 break;
111 default:
112 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
113 break;
114 }
115 }
116
117 static void
gst_player_video_overlay_video_renderer_finalize(GObject * object)118 gst_player_video_overlay_video_renderer_finalize (GObject * object)
119 {
120 GstPlayerVideoOverlayVideoRenderer *self =
121 GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (object);
122
123 if (self->video_overlay)
124 gst_object_unref (self->video_overlay);
125
126 if (self->video_sink)
127 gst_object_unref (self->video_sink);
128
129 G_OBJECT_CLASS
130 (gst_player_video_overlay_video_renderer_parent_class)->finalize (object);
131 }
132
133 static void
gst_player_video_overlay_video_renderer_class_init(GstPlayerVideoOverlayVideoRendererClass * klass)134 gst_player_video_overlay_video_renderer_class_init
135 (GstPlayerVideoOverlayVideoRendererClass * klass)
136 {
137 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
138
139 gobject_class->set_property =
140 gst_player_video_overlay_video_renderer_set_property;
141 gobject_class->get_property =
142 gst_player_video_overlay_video_renderer_get_property;
143 gobject_class->finalize = gst_player_video_overlay_video_renderer_finalize;
144
145 video_overlay_video_renderer_param_specs
146 [VIDEO_OVERLAY_VIDEO_RENDERER_PROP_WINDOW_HANDLE] =
147 g_param_spec_pointer ("window-handle", "Window Handle",
148 "Window handle to embed the video into",
149 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
150
151 video_overlay_video_renderer_param_specs
152 [VIDEO_OVERLAY_VIDEO_RENDERER_PROP_VIDEO_SINK] =
153 g_param_spec_object ("video-sink", "Video Sink",
154 "the video output element to use (NULL = default sink)",
155 GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
156
157 g_object_class_install_properties (gobject_class,
158 VIDEO_OVERLAY_VIDEO_RENDERER_PROP_LAST,
159 video_overlay_video_renderer_param_specs);
160 }
161
162 static void
gst_player_video_overlay_video_renderer_init(GstPlayerVideoOverlayVideoRenderer * self)163 gst_player_video_overlay_video_renderer_init
164 (GstPlayerVideoOverlayVideoRenderer * self)
165 {
166 self->x = self->y = self->width = self->height = -1;
167 self->video_sink = NULL;
168 }
169
gst_player_video_overlay_video_renderer_create_video_sink(GstPlayerVideoRenderer * iface,GstPlayer * player)170 static GstElement *gst_player_video_overlay_video_renderer_create_video_sink
171 (GstPlayerVideoRenderer * iface, GstPlayer * player)
172 {
173 GstElement *video_overlay;
174 GstPlayerVideoOverlayVideoRenderer *self =
175 GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (iface);
176
177 if (self->video_overlay)
178 gst_object_unref (self->video_overlay);
179
180 video_overlay = gst_player_get_pipeline (player);
181 g_return_val_if_fail (GST_IS_VIDEO_OVERLAY (video_overlay), NULL);
182
183 self->video_overlay = GST_VIDEO_OVERLAY (video_overlay);
184
185 gst_video_overlay_set_window_handle (self->video_overlay,
186 (guintptr) self->window_handle);
187 if (self->width != -1 || self->height != -1)
188 gst_video_overlay_set_render_rectangle (self->video_overlay, self->x,
189 self->y, self->width, self->height);
190
191 return self->video_sink;
192 }
193
194 static void
gst_player_video_overlay_video_renderer_interface_init(GstPlayerVideoRendererInterface * iface)195 gst_player_video_overlay_video_renderer_interface_init
196 (GstPlayerVideoRendererInterface * iface)
197 {
198 iface->create_video_sink =
199 gst_player_video_overlay_video_renderer_create_video_sink;
200 }
201
202 /**
203 * gst_player_video_overlay_video_renderer_new:
204 * @window_handle: (allow-none): Window handle to use or %NULL
205 *
206 * Returns: (transfer full):
207 */
208 GstPlayerVideoRenderer *
gst_player_video_overlay_video_renderer_new(gpointer window_handle)209 gst_player_video_overlay_video_renderer_new (gpointer window_handle)
210 {
211 return g_object_new (GST_TYPE_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER,
212 "window-handle", window_handle, NULL);
213 }
214
215 /**
216 * gst_player_video_overlay_video_renderer_new_with_sink:
217 * @window_handle: (allow-none): Window handle to use or %NULL
218 * @video_sink: (transfer floating): the custom video_sink element to be set for the video renderer
219 *
220 * Returns: (transfer full):
221 *
222 * Since: 1.12
223 */
224 GstPlayerVideoRenderer *
gst_player_video_overlay_video_renderer_new_with_sink(gpointer window_handle,GstElement * video_sink)225 gst_player_video_overlay_video_renderer_new_with_sink (gpointer window_handle,
226 GstElement * video_sink)
227 {
228 return g_object_new (GST_TYPE_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER,
229 "window-handle", window_handle, "video-sink", video_sink, NULL);
230 }
231
232 /**
233 * gst_player_video_overlay_video_renderer_set_window_handle:
234 * @self: #GstPlayerVideoRenderer instance
235 * @window_handle: handle referencing to the platform specific window
236 *
237 * Sets the platform specific window handle into which the video
238 * should be rendered
239 **/
gst_player_video_overlay_video_renderer_set_window_handle(GstPlayerVideoOverlayVideoRenderer * self,gpointer window_handle)240 void gst_player_video_overlay_video_renderer_set_window_handle
241 (GstPlayerVideoOverlayVideoRenderer * self, gpointer window_handle)
242 {
243 g_return_if_fail (GST_IS_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
244
245 g_object_set (self, "window-handle", window_handle, NULL);
246 }
247
248 /**
249 * gst_player_video_overlay_video_renderer_get_window_handle:
250 * @self: #GstPlayerVideoRenderer instance
251 *
252 * Returns: (transfer none): The currently set, platform specific window
253 * handle
254 */
255 gpointer
gst_player_video_overlay_video_renderer_get_window_handle(GstPlayerVideoOverlayVideoRenderer * self)256 gst_player_video_overlay_video_renderer_get_window_handle
257 (GstPlayerVideoOverlayVideoRenderer * self) {
258 gpointer window_handle;
259
260 g_return_val_if_fail (GST_IS_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (self),
261 NULL);
262
263 g_object_get (self, "window-handle", &window_handle, NULL);
264
265 return window_handle;
266 }
267
268 /**
269 * gst_player_video_overlay_video_renderer_expose:
270 * @self: a #GstPlayerVideoOverlayVideoRenderer instance.
271 *
272 * Tell an overlay that it has been exposed. This will redraw the current frame
273 * in the drawable even if the pipeline is PAUSED.
274 */
gst_player_video_overlay_video_renderer_expose(GstPlayerVideoOverlayVideoRenderer * self)275 void gst_player_video_overlay_video_renderer_expose
276 (GstPlayerVideoOverlayVideoRenderer * self)
277 {
278 g_return_if_fail (GST_IS_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
279
280 if (self->video_overlay)
281 gst_video_overlay_expose (self->video_overlay);
282 }
283
284 /**
285 * gst_player_video_overlay_video_renderer_set_render_rectangle:
286 * @self: a #GstPlayerVideoOverlayVideoRenderer instance
287 * @x: the horizontal offset of the render area inside the window
288 * @y: the vertical offset of the render area inside the window
289 * @width: the width of the render area inside the window
290 * @height: the height of the render area inside the window
291 *
292 * Configure a subregion as a video target within the window set by
293 * gst_player_video_overlay_video_renderer_set_window_handle(). If this is not
294 * used or not supported the video will fill the area of the window set as the
295 * overlay to 100%. By specifying the rectangle, the video can be overlaid to
296 * a specific region of that window only. After setting the new rectangle one
297 * should call gst_player_video_overlay_video_renderer_expose() to force a
298 * redraw. To unset the region pass -1 for the @width and @height parameters.
299 *
300 * This method is needed for non fullscreen video overlay in UI toolkits that
301 * do not support subwindows.
302 *
303 */
gst_player_video_overlay_video_renderer_set_render_rectangle(GstPlayerVideoOverlayVideoRenderer * self,gint x,gint y,gint width,gint height)304 void gst_player_video_overlay_video_renderer_set_render_rectangle
305 (GstPlayerVideoOverlayVideoRenderer * self, gint x, gint y, gint width,
306 gint height)
307 {
308 g_return_if_fail (GST_IS_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
309
310 self->x = x;
311 self->y = y;
312 self->width = width;
313 self->height = height;
314
315 if (self->video_overlay)
316 gst_video_overlay_set_render_rectangle (self->video_overlay,
317 x, y, width, height);
318 }
319
320 /**
321 * gst_player_video_overlay_video_renderer_get_render_rectangle:
322 * @self: a #GstPlayerVideoOverlayVideoRenderer instance
323 * @x: (out) (allow-none): the horizontal offset of the render area inside the window
324 * @y: (out) (allow-none): the vertical offset of the render area inside the window
325 * @width: (out) (allow-none): the width of the render area inside the window
326 * @height: (out) (allow-none): the height of the render area inside the window
327 *
328 * Return the currently configured render rectangle. See gst_player_video_overlay_video_renderer_set_render_rectangle()
329 * for details.
330 *
331 */
gst_player_video_overlay_video_renderer_get_render_rectangle(GstPlayerVideoOverlayVideoRenderer * self,gint * x,gint * y,gint * width,gint * height)332 void gst_player_video_overlay_video_renderer_get_render_rectangle
333 (GstPlayerVideoOverlayVideoRenderer * self, gint * x, gint * y,
334 gint * width, gint * height)
335 {
336 g_return_if_fail (GST_IS_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER (self));
337
338 if (x)
339 *x = self->x;
340 if (y)
341 *y = self->y;
342 if (width)
343 *width = self->width;
344 if (height)
345 *height = self->height;
346 }
347